1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2
3 /* NetworkManager -- Network link manager
4 *
5 * Ray Strode <rstrode@redhat.com>
6 * Dan Williams <dcbw@redhat.com>
7 * Tambet Ingo <tambet@gmail.com>
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the
21 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 * Boston, MA 02110-1301 USA.
23 *
24 * (C) Copyright 2005 - 2013 Red Hat, Inc.
25 */
26
27 #include "config.h"
28
29 #include <string.h>
30 #include <stdlib.h>
31 #include <netinet/ether.h>
32 #include <linux/if_infiniband.h>
33 #include <uuid/uuid.h>
34
35 #include "nm-utils.h"
36 #include "nm-utils-private.h"
37 #include "nm-glib-compat.h"
38 #include "nm-dbus-glib-types.h"
39 #include "crypto.h"
40
41 /**
42 * SECTION:nm-utils
43 * @short_description: Utility functions
44 * @include: nm-utils.h
45 *
46 * A collection of utility functions for working SSIDs, IP addresses, WiFi
47 * access points and devices, among other things.
48 */
49
50 struct EncodingTriplet
51 {
52 const char *encoding1;
53 const char *encoding2;
54 const char *encoding3;
55 };
56
57 struct IsoLangToEncodings
58 {
59 const char * lang;
60 struct EncodingTriplet encodings;
61 };
62
63 /* 5-letter language codes */
64 static const struct IsoLangToEncodings isoLangEntries5[] =
65 {
66 /* Simplified Chinese */
67 { "zh_cn", {"euc-cn", "gb2312", "gb18030"} }, /* PRC */
68 { "zh_sg", {"euc-cn", "gb2312", "gb18030"} }, /* Singapore */
69
70 /* Traditional Chinese */
71 { "zh_tw", {"big5", "euc-tw", NULL} }, /* Taiwan */
72 { "zh_hk", {"big5", "euc-tw", "big5-hkcs"} },/* Hong Kong */
73 { "zh_mo", {"big5", "euc-tw", NULL} }, /* Macau */
74
75 /* Table end */
76 { NULL, {NULL, NULL, NULL} }
77 };
78
79 /* 2-letter language codes; we don't care about the other 3 in this table */
80 static const struct IsoLangToEncodings isoLangEntries2[] =
81 {
82 /* Japanese */
83 { "ja", {"euc-jp", "shift_jis", "iso-2022-jp"} },
84
85 /* Korean */
86 { "ko", {"euc-kr", "iso-2022-kr", "johab"} },
87
88 /* Thai */
89 { "th", {"iso-8859-11","windows-874", NULL} },
90
91 /* Central European */
92 { "hu", {"iso-8859-2", "windows-1250", NULL} }, /* Hungarian */
93 { "cs", {"iso-8859-2", "windows-1250", NULL} }, /* Czech */
94 { "hr", {"iso-8859-2", "windows-1250", NULL} }, /* Croatian */
95 { "pl", {"iso-8859-2", "windows-1250", NULL} }, /* Polish */
96 { "ro", {"iso-8859-2", "windows-1250", NULL} }, /* Romanian */
97 { "sk", {"iso-8859-2", "windows-1250", NULL} }, /* Slovakian */
98 { "sl", {"iso-8859-2", "windows-1250", NULL} }, /* Slovenian */
99 { "sh", {"iso-8859-2", "windows-1250", NULL} }, /* Serbo-Croatian */
100
101 /* Cyrillic */
102 { "ru", {"koi8-r", "windows-1251", "iso-8859-5"} }, /* Russian */
103 { "be", {"koi8-r", "windows-1251", "iso-8859-5"} }, /* Belorussian */
104 { "bg", {"windows-1251","koi8-r", "iso-8859-5"} }, /* Bulgarian */
105 { "mk", {"koi8-r", "windows-1251", "iso-8859-5"} }, /* Macedonian */
106 { "sr", {"koi8-r", "windows-1251", "iso-8859-5"} }, /* Serbian */
107 { "uk", {"koi8-u", "koi8-r", "windows-1251"} }, /* Ukranian */
108
109 /* Arabic */
110 { "ar", {"iso-8859-6", "windows-1256", NULL} },
111
112 /* Baltic */
113 { "et", {"iso-8859-4", "windows-1257", NULL} }, /* Estonian */
114 { "lt", {"iso-8859-4", "windows-1257", NULL} }, /* Lithuanian */
115 { "lv", {"iso-8859-4", "windows-1257", NULL} }, /* Latvian */
116
117 /* Greek */
118 { "el", {"iso-8859-7", "windows-1253", NULL} },
119
120 /* Hebrew */
121 { "he", {"iso-8859-8", "windows-1255", NULL} },
122 { "iw", {"iso-8859-8", "windows-1255", NULL} },
123
124 /* Turkish */
125 { "tr", {"iso-8859-9", "windows-1254", NULL} },
126
127 /* Table end */
128 { NULL, {NULL, NULL, NULL} }
129 };
130
131
132 static GHashTable * langToEncodings5 = NULL;
133 static GHashTable * langToEncodings2 = NULL;
134
135 static void
136 init_lang_to_encodings_hash (void)
137 {
138 struct IsoLangToEncodings *enc;
139
140 if (G_UNLIKELY (langToEncodings5 == NULL)) {
141 /* Five-letter codes */
142 enc = (struct IsoLangToEncodings *) &isoLangEntries5[0];
143 langToEncodings5 = g_hash_table_new (g_str_hash, g_str_equal);
144 while (enc->lang) {
145 g_hash_table_insert (langToEncodings5, (gpointer) enc->lang,
146 (gpointer) &enc->encodings);
147 enc++;
148 }
149 }
150
151 if (G_UNLIKELY (langToEncodings2 == NULL)) {
152 /* Two-letter codes */
153 enc = (struct IsoLangToEncodings *) &isoLangEntries2[0];
154 langToEncodings2 = g_hash_table_new (g_str_hash, g_str_equal);
155 while (enc->lang) {
156 g_hash_table_insert (langToEncodings2, (gpointer) enc->lang,
157 (gpointer) &enc->encodings);
158 enc++;
159 }
160 }
161 }
162
163
164 static gboolean
165 get_encodings_for_lang (const char *lang,
166 char **encoding1,
167 char **encoding2,
168 char **encoding3)
169 {
170 struct EncodingTriplet * encodings;
171 gboolean success = FALSE;
172 char * tmp_lang;
173
174 g_return_val_if_fail (lang != NULL, FALSE);
175 g_return_val_if_fail (encoding1 != NULL, FALSE);
176 g_return_val_if_fail (encoding2 != NULL, FALSE);
177 g_return_val_if_fail (encoding3 != NULL, FALSE);
178
179 *encoding1 = "iso-8859-1";
180 *encoding2 = "windows-1251";
181 *encoding3 = NULL;
182
183 init_lang_to_encodings_hash ();
184
185 tmp_lang = g_strdup (lang);
186 if ((encodings = g_hash_table_lookup (langToEncodings5, tmp_lang)))
187 {
188 *encoding1 = (char *) encodings->encoding1;
189 *encoding2 = (char *) encodings->encoding2;
190 *encoding3 = (char *) encodings->encoding3;
191 success = TRUE;
192 }
193
194 /* Truncate tmp_lang to length of 2 */
195 if (strlen (tmp_lang) > 2)
196 tmp_lang[2] = '\0';
197 if (!success && (encodings = g_hash_table_lookup (langToEncodings2, tmp_lang)))
198 {
199 *encoding1 = (char *) encodings->encoding1;
200 *encoding2 = (char *) encodings->encoding2;
201 *encoding3 = (char *) encodings->encoding3;
202 success = TRUE;
203 }
204
205 g_free (tmp_lang);
206 return success;
207 }
208
209 /* init, deinit for libnm_util */
210
211 static gboolean initialized = FALSE;
212
213 /**
214 * nm_utils_init:
215 * @error: location to store error, or %NULL
216 *
217 * Initializes libnm-util; should be called when starting and program that
218 * uses libnm-util. Sets up an atexit() handler to ensure de-initialization
219 * is performed, but calling nm_utils_deinit() to explicitly deinitialize
220 * libnm-util can also be done. This function can be called more than once.
221 *
222 * Returns: TRUE if the initialization was successful, FALSE on failure.
223 **/
224 gboolean
225 nm_utils_init (GError **error)
226 {
227 if (!initialized) {
228 initialized = TRUE;
229
230 if (!crypto_init (error))
231 return FALSE;
232
233 _nm_value_transforms_register ();
234 }
235 return TRUE;
236 }
237
238 /**
239 * nm_utils_deinit:
240 *
241 * Frees all resources used internally by libnm-util. This function is called
242 * from an atexit() handler, set up by nm_utils_init(), but is safe to be called
243 * more than once. Subsequent calls have no effect until nm_utils_init() is
244 * called again.
245 **/
246 void
247 nm_utils_deinit (void)
248 {
249 if (initialized) {
250 crypto_deinit ();
251 initialized = FALSE;
252 }
253 }
254
255 /* ssid helpers */
256
257 /**
258 * nm_utils_ssid_to_utf8:
259 * @ssid: a byte array containing the SSID data
260 *
261 * WiFi SSIDs are byte arrays, they are _not_ strings. Thus, an SSID may
262 * contain embedded NULLs and other unprintable characters. Often it is
263 * useful to print the SSID out for debugging purposes, but that should be the
264 * _only_ use of this function. Do not use this function for any persistent
265 * storage of the SSID, since the printable SSID returned from this function
266 * cannot be converted back into the real SSID of the access point.
267 *
268 * This function does almost everything humanly possible to convert the input
269 * into a printable UTF-8 string, using roughly the following procedure:
270 *
271 * 1) if the input data is already UTF-8 safe, no conversion is performed
272 * 2) attempts to get the current system language from the LANG environment
273 * variable, and depending on the language, uses a table of alternative
274 * encodings to try. For example, if LANG=hu_HU, the table may first try
275 * the ISO-8859-2 encoding, and if that fails, try the Windows-1250 encoding.
276 * If all fallback encodings fail, replaces non-UTF-8 characters with '?'.
277 * 3) If the system language was unable to be determined, falls back to the
278 * ISO-8859-1 encoding, then to the Windows-1251 encoding.
279 * 4) If step 3 fails, replaces non-UTF-8 characters with '?'.
280 *
281 * Again, this function should be used for debugging and display purposes
282 * _only_.
283 *
284 * Returns: (transfer full): an allocated string containing a UTF-8
285 * representation of the SSID, which must be freed by the caller using g_free().
286 * Returns %NULL on errors.
287 **/
288 char *
289 nm_utils_ssid_to_utf8 (const GByteArray *ssid)
290 {
291 char *converted = NULL;
292 char *lang, *e1 = NULL, *e2 = NULL, *e3 = NULL;
293
294 g_return_val_if_fail (ssid != NULL, NULL);
295
296 if (g_utf8_validate ((const gchar *) ssid->data, ssid->len, NULL))
297 return g_strndup ((const gchar *) ssid->data, ssid->len);
298
299 /* LANG may be a good encoding hint */
300 g_get_charset ((const char **)(&e1));
301 if ((lang = getenv ("LANG"))) {
302 char * dot;
303
304 lang = g_ascii_strdown (lang, -1);
305 if ((dot = strchr (lang, '.')))
306 *dot = '\0';
307
308 get_encodings_for_lang (lang, &e1, &e2, &e3);
309 g_free (lang);
310 }
311
312 converted = g_convert ((const gchar *) ssid->data, ssid->len, "UTF-8", e1, NULL, NULL, NULL);
313 if (!converted && e2)
314 converted = g_convert ((const gchar *) ssid->data, ssid->len, "UTF-8", e2, NULL, NULL, NULL);
315
316 if (!converted && e3)
317 converted = g_convert ((const gchar *) ssid->data, ssid->len, "UTF-8", e3, NULL, NULL, NULL);
318
319 if (!converted) {
320 converted = g_convert_with_fallback ((const gchar *) ssid->data, ssid->len,
321 "UTF-8", e1, "?", NULL, NULL, NULL);
322 }
323
324 return converted;
325 }
326
327 /* Shamelessly ripped from the Linux kernel ieee80211 stack */
328 /**
329 * nm_utils_is_empty_ssid:
330 * @ssid: pointer to a buffer containing the SSID data
331 * @len: length of the SSID data in @ssid
332 *
333 * Different manufacturers use different mechanisms for not broadcasting the
334 * AP's SSID. This function attempts to detect blank/empty SSIDs using a
335 * number of known SSID-cloaking methods.
336 *
337 * Returns: TRUE if the SSID is "empty", FALSE if it is not
338 **/
339 gboolean
340 nm_utils_is_empty_ssid (const guint8 * ssid, int len)
341 {
342 /* Single white space is for Linksys APs */
343 if (len == 1 && ssid[0] == ' ')
344 return TRUE;
345
346 /* Otherwise, if the entire ssid is 0, we assume it is hidden */
347 while (len--) {
348 if (ssid[len] != '\0')
349 return FALSE;
350 }
351 return TRUE;
352 }
353
354 #define ESSID_MAX_SIZE 32
355
356 /**
357 * nm_utils_escape_ssid:
358 * @ssid: pointer to a buffer containing the SSID data
359 * @len: length of the SSID data in @ssid
360 *
361 * This function does a quick printable character conversion of the SSID, simply
362 * replacing embedded NULLs and non-printable characters with the hexadecimal
363 * representation of that character. Intended for debugging only, should not
364 * be used for display of SSIDs.
365 *
366 * Returns: pointer to the escaped SSID, which uses an internal static buffer
367 * and will be overwritten by subsequent calls to this function
368 **/
369 const char *
370 nm_utils_escape_ssid (const guint8 * ssid, guint32 len)
371 {
372 static char escaped[ESSID_MAX_SIZE * 2 + 1];
373 const guint8 *s = ssid;
374 char *d = escaped;
375
376 if (nm_utils_is_empty_ssid (ssid, len)) {
377 memcpy (escaped, "<hidden>", sizeof ("<hidden>"));
378 return escaped;
379 }
380
381 len = MIN (len, (guint32) ESSID_MAX_SIZE);
382 while (len--) {
383 if (*s == '\0') {
384 *d++ = '\\';
385 *d++ = '0';
386 s++;
387 } else {
388 *d++ = *s++;
389 }
390 }
391 *d = '\0';
392 return escaped;
393 }
394
395 /**
396 * nm_utils_same_ssid:
397 * @ssid1: first SSID data to compare
398 * @ssid2: second SSID data to compare
399 * @ignore_trailing_null: TRUE to ignore one trailing NULL byte
400 *
401 * Earlier versions of the Linux kernel added a NULL byte to the end of the
402 * SSID to enable easy printing of the SSID on the console or in a terminal,
403 * but this behavior was problematic (SSIDs are simply byte arrays, not strings)
404 * and thus was changed. This function compensates for that behavior at the
405 * cost of some compatibility with odd SSIDs that may legitimately have trailing
406 * NULLs, even though that is functionally pointless.
407 *
408 * Returns: TRUE if the SSIDs are the same, FALSE if they are not
409 **/
410 gboolean
411 nm_utils_same_ssid (const GByteArray * ssid1,
412 const GByteArray * ssid2,
413 gboolean ignore_trailing_null)
414 {
415 guint32 ssid1_len, ssid2_len;
416
417 if (ssid1 == ssid2)
418 return TRUE;
419 if ((ssid1 && !ssid2) || (!ssid1 && ssid2))
420 return FALSE;
421
422 ssid1_len = ssid1->len;
423 ssid2_len = ssid2->len;
424 if (ssid1_len && ssid2_len && ignore_trailing_null) {
425 if (ssid1->data[ssid1_len - 1] == '\0')
426 ssid1_len--;
427 if (ssid2->data[ssid2_len - 1] == '\0')
428 ssid2_len--;
429 }
430
431 if (ssid1_len != ssid2_len)
432 return FALSE;
433
434 return memcmp (ssid1->data, ssid2->data, ssid1_len) == 0 ? TRUE : FALSE;
435 }
436
437 static void
438 value_destroy (gpointer data)
439 {
440 GValue *value = (GValue *) data;
441
442 g_value_unset (value);
443 g_slice_free (GValue, value);
444 }
445
446 static void
447 value_dup (gpointer key, gpointer val, gpointer user_data)
448 {
449 GHashTable *table = (GHashTable *) user_data;
450 GValue *value = (GValue *) val;
451 GValue *dup_value;
452
453 dup_value = g_slice_new0 (GValue);
454 g_value_init (dup_value, G_VALUE_TYPE (val));
455 g_value_copy (value, dup_value);
456
457 g_hash_table_insert (table, g_strdup ((char *) key), dup_value);
458 }
459
460 /**
461 * nm_utils_gvalue_hash_dup:
462 * @hash: a #GHashTable mapping string:GValue
463 *
464 * Utility function to duplicate a hash table of #GValues.
465 *
466 * Returns: (transfer container) (element-type utf8 GObject.Value): a newly allocated duplicated #GHashTable, caller must free the
467 * returned hash with g_hash_table_unref() or g_hash_table_destroy()
468 **/
469 GHashTable *
470 nm_utils_gvalue_hash_dup (GHashTable *hash)
471 {
472 GHashTable *table;
473
474 g_return_val_if_fail (hash != NULL, NULL);
475
476 table = g_hash_table_new_full (g_str_hash, g_str_equal,
477 (GDestroyNotify) g_free,
478 value_destroy);
479
480 g_hash_table_foreach (hash, value_dup, table);
481
482 return table;
483 }
484
485 /**
486 * nm_utils_slist_free: (skip)
487 * @list: a #GSList
488 * @elem_destroy_fn: user function called for each element in @list
489 *
490 * Utility function to free a #GSList.
491 *
492 * Deprecated: use g_slist_free_full().
493 **/
494 void
495 nm_utils_slist_free (GSList *list, GDestroyNotify elem_destroy_fn)
496 {
497 g_slist_free_full (list, elem_destroy_fn);
498 }
499
500 gboolean
501 _nm_utils_string_in_list (const char *str, const char **valid_strings)
502 {
503 int i;
504
505 for (i = 0; valid_strings[i]; i++)
506 if (strcmp (str, valid_strings[i]) == 0)
507 break;
508
509 return valid_strings[i] != NULL;
510 }
511
512 gboolean
513 _nm_utils_string_slist_validate (GSList *list, const char **valid_values)
514 {
515 GSList *iter;
516
517 for (iter = list; iter; iter = iter->next) {
518 if (!_nm_utils_string_in_list ((char *) iter->data, valid_values))
519 return FALSE;
520 }
521
522 return TRUE;
523 }
524
525 gboolean
526 _nm_utils_gvalue_array_validate (GValueArray *elements, guint n_expected, ...)
527 {
528 va_list args;
529 GValue *tmp;
530 int i;
531 gboolean valid = FALSE;
532
533 if (n_expected != elements->n_values)
534 return FALSE;
535
536 va_start (args, n_expected);
537 for (i = 0; i < n_expected; i++) {
538 tmp = g_value_array_get_nth (elements, i);
539 if (G_VALUE_TYPE (tmp) != va_arg (args, GType))
540 goto done;
541 }
542 valid = TRUE;
543
544 done:
545 va_end (args);
546 return valid;
547 }
548
549 static gboolean
550 device_supports_ap_ciphers (guint32 dev_caps,
551 guint32 ap_flags,
552 gboolean static_wep)
553 {
554 gboolean have_pair = FALSE;
555 gboolean have_group = FALSE;
556 /* Device needs to support at least one pairwise and one group cipher */
557
558 /* Pairwise */
559 if (static_wep) {
560 /* Static WEP only uses group ciphers */
561 have_pair = TRUE;
562 } else {
563 if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_WEP40)
564 if (ap_flags & NM_802_11_AP_SEC_PAIR_WEP40)
565 have_pair = TRUE;
566 if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_WEP104)
567 if (ap_flags & NM_802_11_AP_SEC_PAIR_WEP104)
568 have_pair = TRUE;
569 if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_TKIP)
570 if (ap_flags & NM_802_11_AP_SEC_PAIR_TKIP)
571 have_pair = TRUE;
572 if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP)
573 if (ap_flags & NM_802_11_AP_SEC_PAIR_CCMP)
574 have_pair = TRUE;
575 }
576
577 /* Group */
578 if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_WEP40)
579 if (ap_flags & NM_802_11_AP_SEC_GROUP_WEP40)
580 have_group = TRUE;
581 if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_WEP104)
582 if (ap_flags & NM_802_11_AP_SEC_GROUP_WEP104)
583 have_group = TRUE;
584 if (!static_wep) {
585 if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_TKIP)
586 if (ap_flags & NM_802_11_AP_SEC_GROUP_TKIP)
587 have_group = TRUE;
588 if (dev_caps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP)
589 if (ap_flags & NM_802_11_AP_SEC_GROUP_CCMP)
590 have_group = TRUE;
591 }
592
593 return (have_pair && have_group);
594 }
595
596 /**
597 * nm_utils_ap_mode_security_valid:
598 * @type: the security type to check device capabilties against,
599 * e.g. #NMU_SEC_STATIC_WEP
600 * @wifi_caps: bitfield of the capabilities of the specific WiFi device, e.g.
601 * #NM_WIFI_DEVICE_CAP_CIPHER_WEP40
602 *
603 * Given a set of device capabilities, and a desired security type to check
604 * against, determines whether the combination of device capabilities and
605 * desired security type are valid for AP/Hotspot connections.
606 *
607 * Returns: TRUE if the device capabilities are compatible with the desired
608 * @type, FALSE if they are not.
609 *
610 * Since: 0.9.8
611 **/
612 gboolean
613 nm_utils_ap_mode_security_valid (NMUtilsSecurityType type,
614 NMDeviceWifiCapabilities wifi_caps)
615 {
616 if (!(wifi_caps & NM_WIFI_DEVICE_CAP_AP))
617 return FALSE;
618
619 /* Return TRUE for any security that wpa_supplicant's lightweight AP
620 * mode can handle: which is open, WEP, and WPA/WPA2 PSK.
621 */
622 switch (type) {
623 case NMU_SEC_NONE:
624 case NMU_SEC_STATIC_WEP:
625 case NMU_SEC_WPA_PSK:
626 case NMU_SEC_WPA2_PSK:
627 return TRUE;
628 default:
629 break;
630 }
631 return FALSE;
632 }
633
634 /**
635 * nm_utils_security_valid:
636 * @type: the security type to check AP flags and device capabilties against,
637 * e.g. #NMU_SEC_STATIC_WEP
638 * @wifi_caps: bitfield of the capabilities of the specific WiFi device, e.g.
639 * #NM_WIFI_DEVICE_CAP_CIPHER_WEP40
640 * @have_ap: whether the @ap_flags, @ap_wpa, and @ap_rsn arguments are valid
641 * @adhoc: whether the capabilities being tested are from an Ad-Hoc AP (IBSS)
642 * @ap_flags: bitfield of AP capabilities, e.g. #NM_802_11_AP_FLAGS_PRIVACY
643 * @ap_wpa: bitfield of AP capabilties derived from the AP's WPA beacon,
644 * e.g. (#NM_802_11_AP_SEC_PAIR_TKIP | #NM_802_11_AP_SEC_KEY_MGMT_PSK)
645 * @ap_rsn: bitfield of AP capabilties derived from the AP's RSN/WPA2 beacon,
646 * e.g. (#NM_802_11_AP_SEC_PAIR_CCMP | #NM_802_11_AP_SEC_PAIR_TKIP)
647 *
648 * Given a set of device capabilities, and a desired security type to check
649 * against, determines whether the combination of device, desired security
650 * type, and AP capabilities intersect.
651 *
652 * NOTE: this function cannot handle checking security for AP/Hotspot mode;
653 * use nm_utils_ap_mode_security_valid() instead.
654 *
655 * Returns: TRUE if the device capabilities and AP capabilties intersect and are
656 * compatible with the desired @type, FALSE if they are not
657 **/
658 gboolean
659 nm_utils_security_valid (NMUtilsSecurityType type,
660 NMDeviceWifiCapabilities wifi_caps,
661 gboolean have_ap,
662 gboolean adhoc,
663 NM80211ApFlags ap_flags,
664 NM80211ApSecurityFlags ap_wpa,
665 NM80211ApSecurityFlags ap_rsn)
666 {
667 gboolean good = TRUE;
668
669 if (!have_ap) {
670 if (type == NMU_SEC_NONE)
671 return TRUE;
672 if ( (type == NMU_SEC_STATIC_WEP)
673 || ((type == NMU_SEC_DYNAMIC_WEP) && !adhoc)
674 || ((type == NMU_SEC_LEAP) && !adhoc)) {
675 if (wifi_caps & (NM_WIFI_DEVICE_CAP_CIPHER_WEP40 | NM_WIFI_DEVICE_CAP_CIPHER_WEP104))
676 return TRUE;
677 else
678 return FALSE;
679 }
680 }
681
682 switch (type) {
683 case NMU_SEC_NONE:
684 g_assert (have_ap);
685 if (ap_flags & NM_802_11_AP_FLAGS_PRIVACY)
686 return FALSE;
687 if (ap_wpa || ap_rsn)
688 return FALSE;
689 break;
690 case NMU_SEC_LEAP: /* require PRIVACY bit for LEAP? */
691 if (adhoc)
692 return FALSE;
693 /* Fall through */
694 case NMU_SEC_STATIC_WEP:
695 g_assert (have_ap);
696 if (!(ap_flags & NM_802_11_AP_FLAGS_PRIVACY))
697 return FALSE;
698 if (ap_wpa || ap_rsn) {
699 if (!device_supports_ap_ciphers (wifi_caps, ap_wpa, TRUE))
700 if (!device_supports_ap_ciphers (wifi_caps, ap_rsn, TRUE))
701 return FALSE;
702 }
703 break;
704 case NMU_SEC_DYNAMIC_WEP:
705 if (adhoc)
706 return FALSE;
707 g_assert (have_ap);
708 if (ap_rsn || !(ap_flags & NM_802_11_AP_FLAGS_PRIVACY))
709 return FALSE;
710 /* Some APs broadcast minimal WPA-enabled beacons that must be handled */
711 if (ap_wpa) {
712 if (!(ap_wpa & NM_802_11_AP_SEC_KEY_MGMT_802_1X))
713 return FALSE;
714 if (!device_supports_ap_ciphers (wifi_caps, ap_wpa, FALSE))
715 return FALSE;
716 }
717 break;
718 case NMU_SEC_WPA_PSK:
719 if (adhoc)
720 return FALSE; /* FIXME: Kernel WPA Ad-Hoc support is buggy */
721 if (!(wifi_caps & NM_WIFI_DEVICE_CAP_WPA))
722 return FALSE;
723 if (have_ap) {
724 /* Ad-Hoc WPA APs won't necessarily have the PSK flag set, and
725 * they don't have any pairwise ciphers. */
726 if (adhoc) {
727 if ( (ap_wpa & NM_802_11_AP_SEC_GROUP_TKIP)
728 && (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_TKIP))
729 return TRUE;
730 if ( (ap_wpa & NM_802_11_AP_SEC_GROUP_CCMP)
731 && (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP))
732 return TRUE;
733 } else {
734 if (ap_wpa & NM_802_11_AP_SEC_KEY_MGMT_PSK) {
735 if ( (ap_wpa & NM_802_11_AP_SEC_PAIR_TKIP)
736 && (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_TKIP))
737 return TRUE;
738 if ( (ap_wpa & NM_802_11_AP_SEC_PAIR_CCMP)
739 && (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP))
740 return TRUE;
741 }
742 }
743 return FALSE;
744 }
745 break;
746 case NMU_SEC_WPA2_PSK:
747 if (adhoc)
748 return FALSE; /* FIXME: Kernel WPA Ad-Hoc support is buggy */
749 if (!(wifi_caps & NM_WIFI_DEVICE_CAP_RSN))
750 return FALSE;
751 if (have_ap) {
752 /* Ad-Hoc WPA APs won't necessarily have the PSK flag set, and
753 * they don't have any pairwise ciphers, nor any RSA flags yet. */
754 if (adhoc) {
755 if (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_TKIP)
756 return TRUE;
757 if (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP)
758 return TRUE;
759 } else {
760 if (ap_rsn & NM_802_11_AP_SEC_KEY_MGMT_PSK) {
761 if ( (ap_rsn & NM_802_11_AP_SEC_PAIR_TKIP)
762 && (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_TKIP))
763 return TRUE;
764 if ( (ap_rsn & NM_802_11_AP_SEC_PAIR_CCMP)
765 && (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP))
766 return TRUE;
767 }
768 }
769 return FALSE;
770 }
771 break;
772 case NMU_SEC_WPA_ENTERPRISE:
773 if (adhoc)
774 return FALSE;
775 if (!(wifi_caps & NM_WIFI_DEVICE_CAP_WPA))
776 return FALSE;
777 if (have_ap) {
778 if (!(ap_wpa & NM_802_11_AP_SEC_KEY_MGMT_802_1X))
779 return FALSE;
780 /* Ensure at least one WPA cipher is supported */
781 if (!device_supports_ap_ciphers (wifi_caps, ap_wpa, FALSE))
782 return FALSE;
783 }
784 break;
785 case NMU_SEC_WPA2_ENTERPRISE:
786 if (adhoc)
787 return FALSE;
788 if (!(wifi_caps & NM_WIFI_DEVICE_CAP_RSN))
789 return FALSE;
790 if (have_ap) {
791 if (!(ap_rsn & NM_802_11_AP_SEC_KEY_MGMT_802_1X))
792 return FALSE;
793 /* Ensure at least one WPA cipher is supported */
794 if (!device_supports_ap_ciphers (wifi_caps, ap_rsn, FALSE))
795 return FALSE;
796 }
797 break;
798 default:
799 good = FALSE;
800 break;
801 }
802
803 return good;
804 }
805
806 /**
807 * nm_utils_wep_key_valid:
808 * @key: a string that might be a WEP key
809 * @wep_type: the #NMWepKeyType type of the WEP key
810 *
811 * Checks if @key is a valid WEP key
812 *
813 * Returns: %TRUE if @key is a WEP key, %FALSE if not
814 *
815 * Since: 0.9.8
816 */
817 gboolean
818 nm_utils_wep_key_valid (const char *key, NMWepKeyType wep_type)
819 {
820 int keylen, i;
821
822 if (!key)
823 return FALSE;
824
825 keylen = strlen (key);
826 if ( wep_type == NM_WEP_KEY_TYPE_KEY
827 || wep_type == NM_WEP_KEY_TYPE_UNKNOWN) {
828 if (keylen == 10 || keylen == 26) {
829 /* Hex key */
830 for (i = 0; i < keylen; i++) {
831 if (!g_ascii_isxdigit (key[i]))
832 return FALSE;
833 }
834 } else if (keylen == 5 || keylen == 13) {
835 /* ASCII key */
836 for (i = 0; i < keylen; i++) {
837 if (!g_ascii_isprint (key[i]))
838 return FALSE;
839 }
840 } else
841 return FALSE;
842
843 } else if (wep_type == NM_WEP_KEY_TYPE_PASSPHRASE) {
844 if (!keylen || keylen > 64)
845 return FALSE;
846 }
847
848 return TRUE;
849 }
850
851 /**
852 * nm_utils_wpa_psk_valid:
853 * @psk: a string that might be a WPA PSK
854 *
855 * Checks if @psk is a valid WPA PSK
856 *
857 * Returns: %TRUE if @psk is a WPA PSK, %FALSE if not
858 *
859 * Since: 0.9.8
860 */
861 gboolean
862 nm_utils_wpa_psk_valid (const char *psk)
863 {
864 int psklen, i;
865
866 if (!psk)
867 return FALSE;
868
869 psklen = strlen (psk);
870 if (psklen < 8 || psklen > 64)
871 return FALSE;
872
873 if (psklen == 64) {
874 /* Hex PSK */
875 for (i = 0; i < psklen; i++) {
876 if (!g_ascii_isxdigit (psk[i]))
877 return FALSE;
878 }
879 }
880
881 return TRUE;
882 }
883
884 /**
885 * nm_utils_ip4_addresses_from_gvalue:
886 * @value: #GValue containing a #GPtrArray of #GArrays of #guint32s
887 *
888 * Utility function to convert a #GPtrArray of #GArrays of #guint32s representing
889 * a list of NetworkManager IPv4 addresses (which is a tuple of address, gateway,
890 * and prefix) into a #GSList of #NMIP4Address objects. The specific format of
891 * this serialization is not guaranteed to be stable and the #GArray may be
892 * extended in the future.
893 *
894 * Returns: (transfer full) (element-type NetworkManager.IP4Address): a newly allocated #GSList of #NMIP4Address objects
895 **/
896 GSList *
897 nm_utils_ip4_addresses_from_gvalue (const GValue *value)
898 {
899 GPtrArray *addresses;
900 int i;
901 GSList *list = NULL;
902
903 addresses = (GPtrArray *) g_value_get_boxed (value);
904 for (i = 0; addresses && (i < addresses->len); i++) {
905 GArray *array = (GArray *) g_ptr_array_index (addresses, i);
906 NMIP4Address *addr;
907
908 if (array->len < 3) {
909 g_warning ("Ignoring invalid IP4 address");
910 continue;
911 }
912
913 addr = nm_ip4_address_new ();
914 nm_ip4_address_set_address (addr, g_array_index (array, guint32, 0));
915 nm_ip4_address_set_prefix (addr, g_array_index (array, guint32, 1));
916 nm_ip4_address_set_gateway (addr, g_array_index (array, guint32, 2));
917 list = g_slist_prepend (list, addr);
918 }
919
920 return g_slist_reverse (list);
921 }
922
923 /**
924 * nm_utils_ip4_addresses_to_gvalue:
925 * @list: (element-type NMIP4Address): a list of #NMIP4Address objects
926 * @value: a pointer to a #GValue into which to place the converted addresses,
927 * which should be unset by the caller (when no longer needed) with
928 * g_value_unset().
929 *
930 * Utility function to convert a #GSList of #NMIP4Address objects into a
931 * #GPtrArray of #GArrays of #guint32s representing a list of NetworkManager IPv4
932 * addresses (which is a tuple of address, gateway, and prefix). The specific
933 * format of this serialization is not guaranteed to be stable and may be
934 * extended in the future.
935 **/
936 void
937 nm_utils_ip4_addresses_to_gvalue (GSList *list, GValue *value)
938 {
939 GPtrArray *addresses;
940 GSList *iter;
941
942 addresses = g_ptr_array_new ();
943
944 for (iter = list; iter; iter = iter->next) {
945 NMIP4Address *addr = (NMIP4Address *) iter->data;
946 GArray *array;
947 guint32 tmp;
948
949 array = g_array_sized_new (FALSE, TRUE, sizeof (guint32), 3);
950
951 tmp = nm_ip4_address_get_address (addr);
952 g_array_append_val (array, tmp);
953
954 tmp = nm_ip4_address_get_prefix (addr);
955 g_array_append_val (array, tmp);
956
957 tmp = nm_ip4_address_get_gateway (addr);
958 g_array_append_val (array, tmp);
959
960 g_ptr_array_add (addresses, array);
961 }
962
963 g_value_take_boxed (value, addresses);
964 }
965
966 /**
967 * nm_utils_ip4_routes_from_gvalue:
968 * @value: #GValue containing a #GPtrArray of #GArrays of #guint32s
969 *
970 * Utility function to convert a #GPtrArray of #GArrays of #guint32s representing
971 * a list of NetworkManager IPv4 routes (which is a tuple of route, next hop,
972 * prefix, and metric) into a #GSList of #NMIP4Route objects. The specific
973 * format of this serialization is not guaranteed to be stable and may be
974 * extended in the future.
975 *
976 * Returns: (transfer full) (element-type NetworkManager.IP4Route): a newly allocated #GSList of #NMIP4Route objects
977 **/
978 GSList *
979 nm_utils_ip4_routes_from_gvalue (const GValue *value)
980 {
981 GPtrArray *routes;
982 int i;
983 GSList *list = NULL;
984
985 routes = (GPtrArray *) g_value_get_boxed (value);
986 for (i = 0; routes && (i < routes->len); i++) {
987 GArray *array = (GArray *) g_ptr_array_index (routes, i);
988 NMIP4Route *route;
989
990 if (array->len < 4) {
991 g_warning ("Ignoring invalid IP4 route");
992 continue;
993 }
994
995 route = nm_ip4_route_new ();
996 nm_ip4_route_set_dest (route, g_array_index (array, guint32, 0));
997 nm_ip4_route_set_prefix (route, g_array_index (array, guint32, 1));
998 nm_ip4_route_set_next_hop (route, g_array_index (array, guint32, 2));
999 nm_ip4_route_set_metric (route, g_array_index (array, guint32, 3));
1000 list = g_slist_prepend (list, route);
1001 }
1002
1003 return g_slist_reverse (list);
1004 }
1005
1006 /**
1007 * nm_utils_ip4_routes_to_gvalue:
1008 * @list: (element-type NMIP4Route): a list of #NMIP4Route objects
1009 * @value: a pointer to a #GValue into which to place the converted routes,
1010 * which should be unset by the caller (when no longer needed) with
1011 * g_value_unset().
1012 *
1013 * Utility function to convert a #GSList of #NMIP4Route objects into a
1014 * #GPtrArray of #GArrays of #guint32s representing a list of NetworkManager IPv4
1015 * routes (which is a tuple of route, next hop, prefix, and metric). The
1016 * specific format of this serialization is not guaranteed to be stable and may
1017 * be extended in the future.
1018 **/
1019 void
1020 nm_utils_ip4_routes_to_gvalue (GSList *list, GValue *value)
1021 {
1022 GPtrArray *routes;
1023 GSList *iter;
1024
1025 routes = g_ptr_array_new ();
1026
1027 for (iter = list; iter; iter = iter->next) {
1028 NMIP4Route *route = (NMIP4Route *) iter->data;
1029 GArray *array;
1030 guint32 tmp;
1031
1032 array = g_array_sized_new (FALSE, TRUE, sizeof (guint32), 3);
1033
1034 tmp = nm_ip4_route_get_dest (route);
1035 g_array_append_val (array, tmp);
1036
1037 tmp = nm_ip4_route_get_prefix (route);
1038 g_array_append_val (array, tmp);
1039
1040 tmp = nm_ip4_route_get_next_hop (route);
1041 g_array_append_val (array, tmp);
1042
1043 tmp = nm_ip4_route_get_metric (route);
1044 g_array_append_val (array, tmp);
1045
1046 g_ptr_array_add (routes, array);
1047 }
1048
1049 g_value_take_boxed (value, routes);
1050 }
1051
1052 /**
1053 * nm_utils_ip4_netmask_to_prefix:
1054 * @netmask: an IPv4 netmask in network byte order
1055 *
1056 * Returns: the CIDR prefix represented by the netmask
1057 **/
1058 guint32
1059 nm_utils_ip4_netmask_to_prefix (guint32 netmask)
1060 {
1061 guchar *p, *end;
1062 guint32 prefix = 0;
1063
1064 p = (guchar *) &netmask;
1065 end = p + sizeof (guint32);
1066
1067 while ((*p == 0xFF) && p < end) {
1068 prefix += 8;
1069 p++;
1070 }
1071
1072 if (p < end) {
1073 guchar v = *p;
1074
1075 while (v) {
1076 prefix++;
1077 v <<= 1;
1078 }
1079 }
1080
1081 return prefix;
1082 }
1083
1084 /**
1085 * nm_utils_ip4_prefix_to_netmask:
1086 * @prefix: a CIDR prefix
1087 *
1088 * Returns: the netmask represented by the prefix, in network byte order
1089 **/
1090 guint32
1091 nm_utils_ip4_prefix_to_netmask (guint32 prefix)
1092 {
1093 guint32 msk = 0x80000000;
1094 guint32 netmask = 0;
1095
1096 while (prefix > 0) {
1097 netmask |= msk;
1098 msk >>= 1;
1099 prefix--;
1100 }
1101
1102 return (guint32) htonl (netmask);
1103 }
1104
1105
1106 /**
1107 * nm_utils_ip4_get_default_prefix:
1108 * @ip: an IPv4 address (in network byte order)
1109 *
1110 * When the Internet was originally set up, various ranges of IP addresses were
1111 * segmented into three network classes: A, B, and C. This function will return
1112 * a prefix that is associated with the IP address specified defining where it
1113 * falls in the predefined classes.
1114 *
1115 * Returns: the default class prefix for the given IP
1116 **/
1117 /* The function is originally from ipcalc.c of Red Hat's initscripts. */
1118 guint32
1119 nm_utils_ip4_get_default_prefix (guint32 ip)
1120 {
1121 if (((ntohl (ip) & 0xFF000000) >> 24) <= 127)
1122 return 8; /* Class A - 255.0.0.0 */
1123 else if (((ntohl (ip) & 0xFF000000) >> 24) <= 191)
1124 return 16; /* Class B - 255.255.0.0 */
1125
1126 return 24; /* Class C - 255.255.255.0 */
1127 }
1128
1129 /**
1130 * nm_utils_ip6_addresses_from_gvalue:
1131 * @value: gvalue containing a GPtrArray of GValueArrays of (GArray of guchars) and #guint32
1132 *
1133 * Utility function to convert a #GPtrArray of #GValueArrays of (#GArray of guchars) and #guint32
1134 * representing a list of NetworkManager IPv6 addresses (which is a tuple of address,
1135 * prefix, and gateway), into a #GSList of #NMIP6Address objects. The specific format of
1136 * this serialization is not guaranteed to be stable and the #GValueArray may be
1137 * extended in the future.
1138 *
1139 * Returns: (transfer full) (element-type NetworkManager.IP6Address): a newly allocated #GSList of #NMIP6Address objects
1140 **/
1141 GSList *
1142 nm_utils_ip6_addresses_from_gvalue (const GValue *value)
1143 {
1144 GPtrArray *addresses;
1145 int i;
1146 GSList *list = NULL;
1147
1148 addresses = (GPtrArray *) g_value_get_boxed (value);
1149
1150 for (i = 0; addresses && (i < addresses->len); i++) {
1151 GValueArray *elements = (GValueArray *) g_ptr_array_index (addresses, i);
1152 GValue *tmp;
1153 GByteArray *ba_addr;
1154 GByteArray *ba_gw = NULL;
1155 NMIP6Address *addr;
1156 guint32 prefix;
1157
1158 if (elements->n_values < 2 || elements->n_values > 3) {
1159 g_warning ("%s: ignoring invalid IP6 address structure", __func__);
1160 continue;
1161 }
1162
1163 /* Third element (gateway) is optional */
1164 if ( !_nm_utils_gvalue_array_validate (elements, 2, DBUS_TYPE_G_UCHAR_ARRAY, G_TYPE_UINT)
1165 && !_nm_utils_gvalue_array_validate (elements, 3, DBUS_TYPE_G_UCHAR_ARRAY, G_TYPE_UINT, DBUS_TYPE_G_UCHAR_ARRAY)) {
1166 g_warning ("%s: ignoring invalid IP6 address structure", __func__);
1167 continue;
1168 }
1169
1170 tmp = g_value_array_get_nth (elements, 0);
1171 ba_addr = g_value_get_boxed (tmp);
1172 if (ba_addr->len != 16) {
1173 g_warning ("%s: ignoring invalid IP6 address of length %d",
1174 __func__, ba_addr->len);
1175 continue;
1176 }
1177
1178 tmp = g_value_array_get_nth (elements, 1);
1179 prefix = g_value_get_uint (tmp);
1180 if (prefix > 128) {
1181 g_warning ("%s: ignoring invalid IP6 prefix %d",
1182 __func__, prefix);
1183 continue;
1184 }
1185
1186 if (elements->n_values == 3) {
1187 tmp = g_value_array_get_nth (elements, 2);
1188 ba_gw = g_value_get_boxed (tmp);
1189 if (ba_gw->len != 16) {
1190 g_warning ("%s: ignoring invalid IP6 gateway address of length %d",
1191 __func__, ba_gw->len);
1192 continue;
1193 }
1194 }
1195
1196 addr = nm_ip6_address_new ();
1197 nm_ip6_address_set_prefix (addr, prefix);
1198 nm_ip6_address_set_address (addr, (const struct in6_addr *) ba_addr->data);
1199 if (ba_gw)
1200 nm_ip6_address_set_gateway (addr, (const struct in6_addr *) ba_gw->data);
1201
1202 list = g_slist_prepend (list, addr);
1203 }
1204
1205 return g_slist_reverse (list);
1206 }
1207
1208 /**
1209 * nm_utils_ip6_addresses_to_gvalue:
1210 * @list: (element-type NMIP6Address): a list of #NMIP6Address objects
1211 * @value: a pointer to a #GValue into which to place the converted addresses,
1212 * which should be unset by the caller (when no longer needed) with
1213 * g_value_unset().
1214 *
1215 * Utility function to convert a #GSList of #NMIP6Address objects into a
1216 * #GPtrArray of #GValueArrays representing a list of NetworkManager IPv6 addresses
1217 * (which is a tuple of address, prefix, and gateway). The specific format of
1218 * this serialization is not guaranteed to be stable and may be extended in the
1219 * future.
1220 **/
1221 void
1222 nm_utils_ip6_addresses_to_gvalue (GSList *list, GValue *value)
1223 {
1224 GPtrArray *addresses;
1225 GSList *iter;
1226
1227 addresses = g_ptr_array_new ();
1228
1229 for (iter = list; iter; iter = iter->next) {
1230 NMIP6Address *addr = (NMIP6Address *) iter->data;
1231 GValueArray *array;
1232 GValue element = G_VALUE_INIT;
1233 GByteArray *ba;
1234
1235 array = g_value_array_new (3);
1236
1237 /* IP address */
1238 g_value_init (&element, DBUS_TYPE_G_UCHAR_ARRAY);
1239 ba = g_byte_array_new ();
1240 g_byte_array_append (ba, (guint8 *) nm_ip6_address_get_address (addr), 16);
1241 g_value_take_boxed (&element, ba);
1242 g_value_array_append (array, &element);
1243 g_value_unset (&element);
1244
1245 /* Prefix */
1246 g_value_init (&element, G_TYPE_UINT);
1247 g_value_set_uint (&element, nm_ip6_address_get_prefix (addr));
1248 g_value_array_append (array, &element);
1249 g_value_unset (&element);
1250
1251 /* Gateway */
1252 g_value_init (&element, DBUS_TYPE_G_UCHAR_ARRAY);
1253 ba = g_byte_array_new ();
1254 g_byte_array_append (ba, (guint8 *) nm_ip6_address_get_gateway (addr), 16);
1255 g_value_take_boxed (&element, ba);
1256 g_value_array_append (array, &element);
1257 g_value_unset (&element);
1258
1259 g_ptr_array_add (addresses, array);
1260 }
1261
1262 g_value_take_boxed (value, addresses);
1263 }
1264
1265 /**
1266 * nm_utils_ip6_routes_from_gvalue:
1267 * @value: #GValue containing a #GPtrArray of #GValueArrays of (#GArray of #guchars), #guint32,
1268 * (#GArray of #guchars), and #guint32
1269 *
1270 * Utility function #GPtrArray of #GValueArrays of (#GArray of #guchars), #guint32,
1271 * (#GArray of #guchars), and #guint32 representing a list of NetworkManager IPv6
1272 * routes (which is a tuple of destination, prefix, next hop, and metric)
1273 * into a #GSList of #NMIP6Route objects. The specific format of this serialization
1274 * is not guaranteed to be stable and may be extended in the future.
1275 *
1276 * Returns: (transfer full) (element-type NetworkManager.IP6Route): a newly allocated #GSList of #NMIP6Route objects
1277 **/
1278 GSList *
1279 nm_utils_ip6_routes_from_gvalue (const GValue *value)
1280 {
1281 GPtrArray *routes;
1282 int i;
1283 GSList *list = NULL;
1284
1285 routes = (GPtrArray *) g_value_get_boxed (value);
1286 for (i = 0; routes && (i < routes->len); i++) {
1287 GValueArray *route_values = (GValueArray *) g_ptr_array_index (routes, i);
1288 GByteArray *dest, *next_hop;
1289 guint prefix, metric;
1290 NMIP6Route *route;
1291
1292 if (!_nm_utils_gvalue_array_validate (route_values, 4,
1293 DBUS_TYPE_G_UCHAR_ARRAY,
1294 G_TYPE_UINT,
1295 DBUS_TYPE_G_UCHAR_ARRAY,
1296 G_TYPE_UINT)) {
1297 g_warning ("Ignoring invalid IP6 route");
1298 continue;
1299 }
1300
1301 dest = g_value_get_boxed (g_value_array_get_nth (route_values, 0));
1302 if (dest->len != 16) {
1303 g_warning ("%s: ignoring invalid IP6 dest address of length %d",
1304 __func__, dest->len);
1305 continue;
1306 }
1307
1308 prefix = g_value_get_uint (g_value_array_get_nth (route_values, 1));
1309
1310 next_hop = g_value_get_boxed (g_value_array_get_nth (route_values, 2));
1311 if (next_hop->len != 16) {
1312 g_warning ("%s: ignoring invalid IP6 next_hop address of length %d",
1313 __func__, next_hop->len);
1314 continue;
1315 }
1316
1317 metric = g_value_get_uint (g_value_array_get_nth (route_values, 3));
1318
1319 route = nm_ip6_route_new ();
1320 nm_ip6_route_set_dest (route, (struct in6_addr *)dest->data);
1321 nm_ip6_route_set_prefix (route, prefix);
1322 nm_ip6_route_set_next_hop (route, (struct in6_addr *)next_hop->data);
1323 nm_ip6_route_set_metric (route, metric);
1324 list = g_slist_prepend (list, route);
1325 }
1326
1327 return g_slist_reverse (list);
1328 }
1329
1330 /**
1331 * nm_utils_ip6_routes_to_gvalue:
1332 * @list: (element-type NMIP6Route): a list of #NMIP6Route objects
1333 * @value: a pointer to a #GValue into which to place the converted routes,
1334 * which should be unset by the caller (when no longer needed) with
1335 * g_value_unset().
1336 *
1337 * Utility function to convert a #GSList of #NMIP6Route objects into a #GPtrArray of
1338 * #GValueArrays of (#GArray of #guchars), #guint32, (#GArray of #guchars), and #guint32
1339 * representing a list of NetworkManager IPv6 routes (which is a tuple of destination,
1340 * prefix, next hop, and metric). The specific format of this serialization is not
1341 * guaranteed to be stable and may be extended in the future.
1342 **/
1343 void
1344 nm_utils_ip6_routes_to_gvalue (GSList *list, GValue *value)
1345 {
1346 GPtrArray *routes;
1347 GSList *iter;
1348
1349 routes = g_ptr_array_new ();
1350
1351 for (iter = list; iter; iter = iter->next) {
1352 NMIP6Route *route = (NMIP6Route *) iter->data;
1353 GValueArray *array;
1354 const struct in6_addr *addr;
1355 GByteArray *ba;
1356 GValue element = G_VALUE_INIT;
1357
1358 array = g_value_array_new (4);
1359
1360 g_value_init (&element, DBUS_TYPE_G_UCHAR_ARRAY);
1361 addr = nm_ip6_route_get_dest (route);
1362 ba = g_byte_array_new ();
1363 g_byte_array_append (ba, (guchar *)addr, sizeof (*addr));
1364 g_value_take_boxed (&element, ba);
1365 g_value_array_append (array, &element);
1366 g_value_unset (&element);
1367
1368 g_value_init (&element, G_TYPE_UINT);
1369 g_value_set_uint (&element, nm_ip6_route_get_prefix (route));
1370 g_value_array_append (array, &element);
1371 g_value_unset (&element);
1372
1373 g_value_init (&element, DBUS_TYPE_G_UCHAR_ARRAY);
1374 addr = nm_ip6_route_get_next_hop (route);
1375 ba = g_byte_array_new ();
1376 g_byte_array_append (ba, (guchar *)addr, sizeof (*addr));
1377 g_value_take_boxed (&element, ba);
1378 g_value_array_append (array, &element);
1379 g_value_unset (&element);
1380
1381 g_value_init (&element, G_TYPE_UINT);
1382 g_value_set_uint (&element, nm_ip6_route_get_metric (route));
1383 g_value_array_append (array, &element);
1384 g_value_unset (&element);
1385
1386 g_ptr_array_add (routes, array);
1387 }
1388
1389 g_value_take_boxed (value, routes);
1390 }
1391
1392 /**
1393 * nm_utils_ip6_dns_from_gvalue: (skip)
1394 * @value: a #GValue
1395 *
1396 * Converts a #GValue containing a #GPtrArray of IP6 DNS, represented as
1397 * #GByteArrays into a #GSList of <literal><type>struct in6_addr</type></literal>s.
1398 *
1399 * Returns: a #GSList of IP6 addresses.
1400 */
1401 GSList *
1402 nm_utils_ip6_dns_from_gvalue (const GValue *value)
1403 {
1404 GPtrArray *dns;
1405 int i;
1406 GSList *list = NULL;
1407
1408 dns = (GPtrArray *) g_value_get_boxed (value);
1409 for (i = 0; dns && (i < dns->len); i++) {
1410 GByteArray *bytearray = (GByteArray *) g_ptr_array_index (dns, i);
1411 struct in6_addr *addr;
1412
1413 if (bytearray->len != 16) {
1414 g_warning ("%s: ignoring invalid IP6 address of length %d",
1415 __func__, bytearray->len);
1416 continue;
1417 }
1418
1419 addr = g_malloc0 (sizeof (struct in6_addr));
1420 memcpy (addr->s6_addr, bytearray->data, bytearray->len);
1421 list = g_slist_prepend (list, addr);
1422 }
1423
1424 return g_slist_reverse (list);
1425 }
1426
1427 /**
1428 * nm_utils_ip6_dns_to_gvalue: (skip)
1429 * @list: a list of #NMIP6Route objects
1430 * @value: a pointer to a #GValue into which to place the converted DNS server
1431 * addresses, which should be unset by the caller (when no longer needed) with
1432 * g_value_unset().
1433 *
1434 * Utility function to convert a #GSList of <literal><type>struct
1435 * in6_addr</type></literal> structs into a #GPtrArray of #GByteArrays
1436 * representing each server's IPv6 addresses in network byte order.
1437 * The specific format of this serialization is not guaranteed to be
1438 * stable and may be extended in the future.
1439 */
1440 void
1441 nm_utils_ip6_dns_to_gvalue (GSList *list, GValue *value)
1442 {
1443 GPtrArray *dns;
1444 GSList *iter;
1445
1446 dns = g_ptr_array_new ();
1447
1448 for (iter = list; iter; iter = iter->next) {
1449 struct in6_addr *addr = (struct in6_addr *) iter->data;
1450 GByteArray *bytearray;
1451
1452 bytearray = g_byte_array_sized_new (16);
1453 g_byte_array_append (bytearray, (guint8 *) addr->s6_addr, 16);
1454 g_ptr_array_add (dns, bytearray);
1455 }
1456
1457 g_value_take_boxed (value, dns);
1458 }
1459
1460 /**
1461 * nm_utils_uuid_generate:
1462 *
1463 * Returns: a newly allocated UUID suitable for use as the #NMSettingConnection
1464 * object's #NMSettingConnection:id: property. Should be freed with g_free()
1465 **/
1466 char *
1467 nm_utils_uuid_generate (void)
1468 {
1469 uuid_t uuid;
1470 char *buf;
1471
1472 buf = g_malloc0 (37);
1473 uuid_generate_random (uuid);
1474 uuid_unparse_lower (uuid, &buf[0]);
1475 return buf;
1476 }
1477
1478 /**
1479 * nm_utils_uuid_generate_from_string:
1480 * @s: a string to use as the seed for the UUID
1481 *
1482 * For a given @s, this function will always return the same UUID.
1483 *
1484 * Returns: a newly allocated UUID suitable for use as the #NMSettingConnection
1485 * object's #NMSettingConnection:id: property
1486 **/
1487 char *
1488 nm_utils_uuid_generate_from_string (const char *s)
1489 {
1490 GError *error = NULL;
1491 uuid_t *uuid;
1492 char *buf = NULL;
1493
1494 if (!nm_utils_init (&error)) {
1495 g_warning ("error initializing crypto: (%d) %s",
1496 error ? error->code : 0,
1497 error ? error->message : "unknown");
1498 if (error)
1499 g_error_free (error);
1500 return NULL;
1501 }
1502
1503 uuid = g_malloc0 (sizeof (*uuid));
1504 if (!crypto_md5_hash (NULL, 0, s, strlen (s), (char *) uuid, sizeof (*uuid), &error)) {
1505 g_warning ("error generating UUID: (%d) %s",
1506 error ? error->code : 0,
1507 error ? error->message : "unknown");
1508 if (error)
1509 g_error_free (error);
1510 goto out;
1511 }
1512
1513 buf = g_malloc0 (37);
1514 uuid_unparse_lower (*uuid, &buf[0]);
1515
1516 out:
1517 g_free (uuid);
1518 return buf;
1519 }
1520
1521 static char *
1522 make_key (const char *salt,
1523 const gsize salt_len,
1524 const char *password,
1525 gsize *out_len,
1526 GError **error)
1527 {
1528 char *key;
1529 guint32 digest_len = 24; /* DES-EDE3-CBC */
1530
1531 g_return_val_if_fail (salt != NULL, NULL);
1532 g_return_val_if_fail (salt_len >= 8, NULL);
1533 g_return_val_if_fail (password != NULL, NULL);
1534 g_return_val_if_fail (out_len != NULL, NULL);
1535
1536 key = g_malloc0 (digest_len + 1);
1537
1538 if (!crypto_md5_hash (salt, salt_len, password, strlen (password), key, digest_len, error)) {
1539 *out_len = 0;
1540 memset (key, 0, digest_len);
1541 g_free (key);
1542 key = NULL;
1543 } else
1544 *out_len = digest_len;
1545
1546 return key;
1547 }
1548
1549 /**
1550 * nm_utils_rsa_key_encrypt:
1551 * @data: RSA private key data to be encrypted
1552 * @in_password: (allow-none): existing password to use, if any
1553 * @out_password: (out) (allow-none): if @in_password was %NULL, a random password will be generated
1554 * and returned in this argument
1555 * @error: detailed error information on return, if an error occurred
1556 *
1557 * Encrypts the given RSA private key data with the given password (or generates
1558 * a password if no password was given) and converts the data to PEM format
1559 * suitable for writing to a file.
1560 *
1561 * Returns: (transfer full): on success, PEM-formatted data suitable for writing to a PEM-formatted
1562 * certificate/private key file.
1563 **/
1564 GByteArray *
1565 nm_utils_rsa_key_encrypt (const GByteArray *data,
1566 const char *in_password,
1567 char **out_password,
1568 GError **error)
1569 {
1570 char salt[8];
1571 char *key = NULL, *enc = NULL, *pw_buf[32];
1572 gsize key_len = 0, enc_len = 0;
1573 GString *pem = NULL;
1574 char *tmp, *tmp_password = NULL;
1575 int left;
1576 const char *p;
1577 GByteArray *ret = NULL;
1578
1579 g_return_val_if_fail (data != NULL, NULL);
1580 g_return_val_if_fail (data->len > 0, NULL);
1581 if (out_password)
1582 g_return_val_if_fail (*out_password == NULL, NULL);
1583
1584 /* Make the password if needed */
1585 if (!in_password) {
1586 if (!crypto_randomize (pw_buf, sizeof (pw_buf), error))
1587 return NULL;
1588 in_password = tmp_password = nm_utils_bin2hexstr ((const char *) pw_buf, sizeof (pw_buf), -1);
1589 }
1590
1591 if (!crypto_randomize (salt, sizeof (salt), error))
1592 goto out;
1593
1594 key = make_key (&salt[0], sizeof (salt), in_password, &key_len, error);
1595 if (!key)
1596 goto out;
1597
1598 enc = crypto_encrypt (CIPHER_DES_EDE3_CBC, data, salt, sizeof (salt), key, key_len, &enc_len, error);
1599 if (!enc)
1600 goto out;
1601
1602 pem = g_string_sized_new (enc_len * 2 + 100);
1603 g_string_append (pem, "-----BEGIN RSA PRIVATE KEY-----\n");
1604 g_string_append (pem, "Proc-Type: 4,ENCRYPTED\n");
1605
1606 /* Convert the salt to a hex string */
1607 tmp = nm_utils_bin2hexstr ((const char *) salt, sizeof (salt), 16);
1608 g_string_append_printf (pem, "DEK-Info: DES-EDE3-CBC,%s\n\n", tmp);
1609 g_free (tmp);
1610
1611 /* Convert the encrypted key to a base64 string */
1612 p = tmp = g_base64_encode ((const guchar *) enc, enc_len);
1613 left = strlen (tmp);
1614 while (left > 0) {
1615 g_string_append_len (pem, p, (left < 64) ? left : 64);
1616 g_string_append_c (pem, '\n');
1617 left -= 64;
1618 p += 64;
1619 }
1620 g_free (tmp);
1621
1622 g_string_append (pem, "-----END RSA PRIVATE KEY-----\n");
1623
1624 ret = g_byte_array_sized_new (pem->len);
1625 g_byte_array_append (ret, (const unsigned char *) pem->str, pem->len);
1626 if (tmp_password && out_password)
1627 *out_password = g_strdup (tmp_password);
1628
1629 out:
1630 if (key) {
1631 memset (key, 0, key_len);
1632 g_free (key);
1633 }
1634 if (enc) {
1635 memset (enc, 0, enc_len);
1636 g_free (enc);
1637 }
1638 if (pem)
1639 g_string_free (pem, TRUE);
1640
1641 if (tmp_password) {
1642 memset (tmp_password, 0, strlen (tmp_password));
1643 g_free (tmp_password);
1644 }
1645
1646 return ret;
1647 }
1648
1649 /**
1650 * nm_utils_file_is_pkcs12:
1651 * @filename: name of the file to test
1652 *
1653 * Utility function to find out if the @filename is in PKCS#12 format.
1654 *
1655 * Returns: TRUE if the file is PKCS#12, FALSE if it is not
1656 **/
1657 gboolean
1658 nm_utils_file_is_pkcs12 (const char *filename)
1659 {
1660 return crypto_is_pkcs12_file (filename, NULL);
1661 }
1662
1663 /* Band, channel/frequency stuff for wireless */
1664 struct cf_pair {
1665 guint32 chan;
1666 guint32 freq;
1667 };
1668
1669 static struct cf_pair a_table[] = {
1670 /* A band */
1671 { 7, 5035 },
1672 { 8, 5040 },
1673 { 9, 5045 },
1674 { 11, 5055 },
1675 { 12, 5060 },
1676 { 16, 5080 },
1677 { 34, 5170 },
1678 { 36, 5180 },
1679 { 38, 5190 },
1680 { 40, 5200 },
1681 { 42, 5210 },
1682 { 44, 5220 },
1683 { 46, 5230 },
1684 { 48, 5240 },
1685 { 50, 5250 },
1686 { 52, 5260 },
1687 { 56, 5280 },
1688 { 58, 5290 },
1689 { 60, 5300 },
1690 { 64, 5320 },
1691 { 100, 5500 },
1692 { 104, 5520 },
1693 { 108, 5540 },
1694 { 112, 5560 },
1695 { 116, 5580 },
1696 { 120, 5600 },
1697 { 124, 5620 },
1698 { 128, 5640 },
1699 { 132, 5660 },
1700 { 136, 5680 },
1701 { 140, 5700 },
1702 { 149, 5745 },
1703 { 152, 5760 },
1704 { 153, 5765 },
1705 { 157, 5785 },
1706 { 160, 5800 },
1707 { 161, 5805 },
1708 { 165, 5825 },
1709 { 183, 4915 },
1710 { 184, 4920 },
1711 { 185, 4925 },
1712 { 187, 4935 },
1713 { 188, 4945 },
1714 { 192, 4960 },
1715 { 196, 4980 },
1716 { 0, -1 }
1717 };
1718
1719 static struct cf_pair bg_table[] = {
1720 /* B/G band */
1721 { 1, 2412 },
1722 { 2, 2417 },
1723 { 3, 2422 },
1724 { 4, 2427 },
1725 { 5, 2432 },
1726 { 6, 2437 },
1727 { 7, 2442 },
1728 { 8, 2447 },
1729 { 9, 2452 },
1730 { 10, 2457 },
1731 { 11, 2462 },
1732 { 12, 2467 },
1733 { 13, 2472 },
1734 { 14, 2484 },
1735 { 0, -1 }
1736 };
1737
1738 /**
1739 * nm_utils_wifi_freq_to_channel:
1740 * @freq: frequency
1741 *
1742 * Utility function to translate a WiFi frequency to its corresponding channel.
1743 *
1744 * Returns: the channel represented by the frequency or 0
1745 **/
1746 guint32
1747 nm_utils_wifi_freq_to_channel (guint32 freq)
1748 {
1749 int i = 0;
1750
1751 if (freq > 4900) {
1752 while (a_table[i].chan && (a_table[i].freq != freq))
1753 i++;
1754 return a_table[i].chan;
1755 } else {
1756 while (bg_table[i].chan && (bg_table[i].freq != freq))
1757 i++;
1758 return bg_table[i].chan;
1759 }
1760
1761 return 0;
1762 }
1763
1764 /**
1765 * nm_utils_wifi_channel_to_freq:
1766 * @channel: channel
1767 * @band: frequency band for wireless ("a" or "bg")
1768 *
1769 * Utility function to translate a WiFi channel to its corresponding frequency.
1770 *
1771 * Returns: the frequency represented by the channel of the band,
1772 * or -1 when the freq is invalid, or 0 when the band
1773 * is invalid
1774 **/
1775 guint32
1776 nm_utils_wifi_channel_to_freq (guint32 channel, const char *band)
1777 {
1778 int i = 0;
1779
1780 if (!strcmp (band, "a")) {
1781 while (a_table[i].chan && (a_table[i].chan != channel))
1782 i++;
1783 return a_table[i].freq;
1784 } else if (!strcmp (band, "bg")) {
1785 while (bg_table[i].chan && (bg_table[i].chan != channel))
1786 i++;
1787 return bg_table[i].freq;
1788 }
1789
1790 return 0;
1791 }
1792
1793 /**
1794 * nm_utils_wifi_find_next_channel:
1795 * @channel: current channel
1796 * @direction: whether going downward (0 or less) or upward (1 or more)
1797 * @band: frequency band for wireless ("a" or "bg")
1798 *
1799 * Utility function to find out next/previous WiFi channel for a channel.
1800 *
1801 * Returns: the next channel in the specified direction or 0
1802 **/
1803 guint32
1804 nm_utils_wifi_find_next_channel (guint32 channel, int direction, char *band)
1805 {
1806 size_t a_size = sizeof (a_table) / sizeof (struct cf_pair);
1807 size_t bg_size = sizeof (bg_table) / sizeof (struct cf_pair);
1808 struct cf_pair *pair = NULL;
1809
1810 if (!strcmp (band, "a")) {
1811 if (channel < a_table[0].chan)
1812 return a_table[0].chan;
1813 if (channel > a_table[a_size - 2].chan)
1814 return a_table[a_size - 2].chan;
1815 pair = &a_table[0];
1816 } else if (!strcmp (band, "bg")) {
1817 if (channel < bg_table[0].chan)
1818 return bg_table[0].chan;
1819 if (channel > bg_table[bg_size - 2].chan)
1820 return bg_table[bg_size - 2].chan;
1821 pair = &bg_table[0];
1822 } else {
1823 g_assert_not_reached ();
1824 return 0;
1825 }
1826
1827 while (pair->chan) {
1828 if (channel == pair->chan)
1829 return channel;
1830 if ((channel < (pair+1)->chan) && (channel > pair->chan)) {
1831 if (direction > 0)
1832 return (pair+1)->chan;
1833 else
1834 return pair->chan;
1835 }
1836 pair++;
1837 }
1838 return 0;
1839 }
1840
1841 /**
1842 * nm_utils_wifi_is_channel_valid:
1843 * @channel: channel
1844 * @band: frequency band for wireless ("a" or "bg")
1845 *
1846 * Utility function to verify WiFi channel validity.
1847 *
1848 * Returns: TRUE or FALSE
1849 **/
1850 gboolean
1851 nm_utils_wifi_is_channel_valid (guint32 channel, const char *band)
1852 {
1853 struct cf_pair *table = NULL;
1854 int i = 0;
1855
1856 if (!strcmp (band, "a"))
1857 table = a_table;
1858 else if (!strcmp (band, "bg"))
1859 table = bg_table;
1860 else
1861 return FALSE;
1862
1863 while (table[i].chan && (table[i].chan != channel))
1864 i++;
1865
1866 if (table[i].chan != 0)
1867 return TRUE;
1868 else
1869 return FALSE;
1870 }
1871
1872 /**
1873 * nm_utils_hwaddr_len:
1874 * @type: the type of address; either %ARPHRD_ETHER or %ARPHRD_INFINIBAND
1875 *
1876 * Returns the length in octets of a hardware address of type @type.
1877 *
1878 * Note that this only accepts %ARPHRD_ETHER and %ARPHRD_INFINIBAND,
1879 * not other types.
1880 *
1881 * Return value: the length
1882 */
1883 int
1884 nm_utils_hwaddr_len (int type)
1885 {
1886 if (type == ARPHRD_ETHER)
1887 return ETH_ALEN;
1888 else if (type == ARPHRD_INFINIBAND)
1889 return INFINIBAND_ALEN;
1890 else
1891 g_return_val_if_reached (-1);
1892 }
1893
1894 /**
1895 * nm_utils_hwaddr_type:
1896 * @len: the length of hardware address in bytes
1897 *
1898 * Returns the type (either %ARPHRD_ETHER or %ARPHRD_INFINIBAND) of
1899 * the raw address given its length.
1900 *
1901 * Return value: the type, either %ARPHRD_ETHER or %ARPHRD_INFINIBAND.
1902 *
1903 * Deprecated: This could not be extended to cover other types, since
1904 * there is not a one-to-one mapping between types and lengths. This
1905 * was mostly only used to get a type to pass to
1906 * nm_utils_hwaddr_ntoa() or nm_utils_hwaddr_aton() when you only had
1907 * a length; but you can just use nm_utils_hwaddr_ntoa_len() or
1908 * nm_utils_hwaddr_aton_len() now instead.
1909 */
1910 int
1911 nm_utils_hwaddr_type (int len)
1912 {
1913 if (len == ETH_ALEN)
1914 return ARPHRD_ETHER;
1915 else if (len == INFINIBAND_ALEN)
1916 return ARPHRD_INFINIBAND;
1917 else
1918 g_return_val_if_reached (-1);
1919 }
1920
1921 #define HEXVAL(c) ((c) <= '9' ? (c) - '0' : ((c) & 0x4F) - 'A' + 10)
1922
1923 /**
1924 * nm_utils_hwaddr_aton:
1925 * @asc: the ASCII representation of a hardware address
1926 * @type: the type of address; either %ARPHRD_ETHER or %ARPHRD_INFINIBAND
1927 * @buffer: buffer to store the result into
1928 *
1929 * Parses @asc and converts it to binary form in @buffer. See
1930 * nm_utils_hwaddr_atoba() if you'd rather have the result in a
1931 * #GByteArray.
1932 *
1933 * See also nm_utils_hwaddr_aton_len(), which takes an output length
1934 * instead of a type.
1935 *
1936 * Return value: @buffer, or %NULL if @asc couldn't be parsed
1937 */
1938 guint8 *
1939 nm_utils_hwaddr_aton (const char *asc, int type, gpointer buffer)
1940 {
1941 return nm_utils_hwaddr_aton_len (asc, buffer, nm_utils_hwaddr_len (type));
1942 }
1943
1944 /**
1945 * nm_utils_hwaddr_atoba:
1946 * @asc: the ASCII representation of a hardware address
1947 * @type: the type of address; either %ARPHRD_ETHER or %ARPHRD_INFINIBAND
1948 *
1949 * Parses @asc and converts it to binary form in a #GByteArray. See
1950 * nm_utils_hwaddr_aton() if you don't want a #GByteArray.
1951 *
1952 * Return value: (transfer full): a new #GByteArray, or %NULL if @asc couldn't
1953 * be parsed
1954 */
1955 GByteArray *
1956 nm_utils_hwaddr_atoba (const char *asc, int type)
1957 {
1958 GByteArray *ba;
1959 int len = nm_utils_hwaddr_len (type);
1960
1961 ba = g_byte_array_sized_new (len);
1962 ba->len = len;
1963 if (!nm_utils_hwaddr_aton (asc, type, ba->data)) {
1964 g_byte_array_unref (ba);
1965 return NULL;
1966 }
1967
1968 return ba;
1969 }
1970
1971 /**
1972 * nm_utils_hwaddr_ntoa:
1973 * @addr: a binary hardware address
1974 * @type: the type of address; either %ARPHRD_ETHER or %ARPHRD_INFINIBAND
1975 *
1976 * Converts @addr to textual form.
1977 *
1978 * See also nm_utils_hwaddr_ntoa_len(), which takes a length instead of
1979 * a type.
1980 *
1981 * Return value: (transfer full): the textual form of @addr
1982 */
1983 char *
1984 nm_utils_hwaddr_ntoa (gconstpointer addr, int type)
1985 {
1986 return nm_utils_hwaddr_ntoa_len (addr, nm_utils_hwaddr_len (type));
1987 }
1988
1989 /**
1990 * nm_utils_hwaddr_aton_len:
1991 * @asc: the ASCII representation of a hardware address
1992 * @buffer: buffer to store the result into
1993 * @length: the expected length in bytes of the result
1994 *
1995 * Parses @asc and converts it to binary form in @buffer.
1996 * Bytes in @asc can be sepatared by colons (:), or hyphens (-), but not mixed.
1997 *
1998 * Return value: @buffer, or %NULL if @asc couldn't be parsed
1999 * or would be shorter or longer than @length.
2000 *
2001 * Since: 0.9.10
2002 */
2003 guint8 *
2004 nm_utils_hwaddr_aton_len (const char *asc, gpointer buffer, gsize length)
2005 {
2006 const char *in = asc;
2007 guint8 *out = (guint8 *)buffer;
2008 char delimiter = '\0';
2009
2010 while (length && *in) {
2011 guint8 d1 = in[0], d2 = in[1];
2012
2013 if (!g_ascii_isxdigit (d1))
2014 return NULL;
2015
2016 /* If there's no leading zero (ie "aa:b:cc") then fake it */
2017 if (d2 && g_ascii_isxdigit (d2)) {
2018 *out++ = (HEXVAL (d1) << 4) + HEXVAL (d2);
2019 in += 2;
2020 } else {
2021 /* Fake leading zero */
2022 *out++ = (HEXVAL ('0') << 4) + HEXVAL (d1);
2023 in += 1;
2024 }
2025
2026 length--;
2027 if (*in) {
2028 if (delimiter == '\0') {
2029 if (*in == ':' || *in == '-')
2030 delimiter = *in;
2031 else
2032 return NULL;
2033 } else {
2034 if (*in != delimiter)
2035 return NULL;
2036 }
2037 in++;
2038 }
2039 }
2040
2041 if (length == 0 && !*in)
2042 return buffer;
2043 else
2044 return NULL;
2045 }
2046
2047 /**
2048 * nm_utils_hwaddr_ntoa_len:
2049 * @addr: a binary hardware address
2050 * @length: the length of @addr
2051 *
2052 * Converts @addr to textual form.
2053 *
2054 * Return value: (transfer full): the textual form of @addr
2055 *
2056 * Since: 0.9.10
2057 */
2058 char *
2059 nm_utils_hwaddr_ntoa_len (gconstpointer addr, gsize length)
2060 {
2061 const guint8 *in = addr;
2062 GString *out = g_string_new (NULL);
2063
2064 while (length--) {
2065 if (out->len)
2066 g_string_append_c (out, ':');
2067 g_string_append_printf (out, "%02X", *in++);
2068 }
2069
2070 return g_string_free (out, FALSE);
2071 }
2072
2073 /**
2074 * nm_utils_hwaddr_valid:
2075 * @asc: the ASCII representation of a hardware address
2076 *
2077 * Parses @asc to see if it is a valid hardware address of some type.
2078 *
2079 * Return value: %TRUE if @asc appears to be a valid hardware address
2080 * of some type, %FALSE if not.
2081 *
2082 * Since: 0.9.10
2083 */
2084 gboolean
2085 nm_utils_hwaddr_valid (const char *asc)
2086 {
2087 guint8 buf[NM_UTILS_HWADDR_LEN_MAX];
2088 int in_len = strlen (asc), out_len;
2089
2090 if ((in_len + 1) % 3 != 0)
2091 return FALSE;
2092 out_len = (in_len + 1) / 3;
2093 if (out_len > NM_UTILS_HWADDR_LEN_MAX)
2094 return FALSE;
2095 return nm_utils_hwaddr_aton_len (asc, buf, out_len) != NULL;
2096 }
2097
2098 /**
2099 * nm_utils_bin2hexstr:
2100 * @bytes: an array of bytes
2101 * @len: the length of the @bytes array
2102 * @final_len: an index where to cut off the returned string, or -1
2103 *
2104 * Converts a byte-array @bytes into a hexadecimal string.
2105 * If @final_len is greater than -1, the returned string is terminated at
2106 * that index (returned_string[final_len] == '\0'),
2107 *
2108 * Return value: (transfer full): the textual form of @bytes
2109 *
2110 * Since: 0.9.10
2111 *
2112 * Code originally by Alex Larsson <alexl@redhat.com> and
2113 * copyright Red Hat, Inc. under terms of the LGPL.
2114 */
2115 char *
2116 nm_utils_bin2hexstr (const char *bytes, int len, int final_len)
2117 {
2118 static char hex_digits[] = "0123456789abcdef";
2119 char *result;
2120 int i;
2121 gsize buflen = (len * 2) + 1;
2122
2123 g_return_val_if_fail (bytes != NULL, NULL);
2124 g_return_val_if_fail (len > 0, NULL);
2125 g_return_val_if_fail (len < 4096, NULL); /* Arbitrary limit */
2126 if (final_len > -1)
2127 g_return_val_if_fail (final_len < buflen, NULL);
2128
2129 result = g_malloc0 (buflen);
2130 for (i = 0; i < len; i++)
2131 {
2132 result[2*i] = hex_digits[(bytes[i] >> 4) & 0xf];
2133 result[2*i+1] = hex_digits[bytes[i] & 0xf];
2134 }
2135 /* Cut converted key off at the correct length for this cipher type */
2136 if (final_len > -1)
2137 result[final_len] = '\0';
2138 else
2139 result[buflen - 1] = '\0';
2140
2141 return result;
2142 }
2143
2144 /* From hostap, Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi> */
2145 /**
2146 * nm_utils_hex2byte:
2147 * @hex: a string representing a hex byte
2148 *
2149 * Converts a hex string (2 characters) into its byte representation.
2150 *
2151 * Return value: a byte, or -1 if @hex doesn't represent a hex byte
2152 *
2153 * Since: 0.9.10
2154 */
2155 int
2156 nm_utils_hex2byte (const char *hex)
2157 {
2158 int a, b;
2159 a = g_ascii_xdigit_value (*hex++);
2160 if (a < 0)
2161 return -1;
2162 b = g_ascii_xdigit_value (*hex++);
2163 if (b < 0)
2164 return -1;
2165 return (a << 4) | b;
2166 }
2167
2168 /**
2169 * nm_utils_hexstr2bin:
2170 * @hex: an hex string
2171 * @len: the length of the @hex string (it has to be even)
2172 *
2173 * Converts a hexadecimal string @hex into a byte-array. The returned array
2174 * length is @len/2.
2175 *
2176 * Return value: (transfer full): a array of bytes, or %NULL on error
2177 *
2178 * Since: 0.9.10
2179 */
2180 char *
2181 nm_utils_hexstr2bin (const char *hex, size_t len)
2182 {
2183 size_t i;
2184 int a;
2185 const char * ipos = hex;
2186 char * buf = NULL;
2187 char * opos;
2188
2189 /* Length must be a multiple of 2 */
2190 if ((len % 2) != 0)
2191 return NULL;
2192
2193 opos = buf = g_malloc0 ((len / 2) + 1);
2194 for (i = 0; i < len; i += 2) {
2195 a = nm_utils_hex2byte (ipos);
2196 if (a < 0) {
2197 g_free (buf);
2198 return NULL;
2199 }
2200 *opos++ = a;
2201 ipos += 2;
2202 }
2203 return buf;
2204 }
2205 /* End from hostap */
2206
2207 /**
2208 * nm_utils_iface_valid_name:
2209 * @name: Name of interface
2210 *
2211 * This function is a 1:1 copy of the kernel's interface validation
2212 * function in net/core/dev.c.
2213 *
2214 * Returns: %TRUE if interface name is valid, otherwise %FALSE is returned.
2215 *
2216 * Since: 0.9.8
2217 */
2218 gboolean
2219 nm_utils_iface_valid_name (const char *name)
2220 {
2221 g_return_val_if_fail (name != NULL, FALSE);
2222
2223 if (*name == '\0')
2224 return FALSE;
2225
2226 if (strlen (name) >= 16)
2227 return FALSE;
2228
2229 if (!strcmp (name, ".") || !strcmp (name, ".."))
2230 return FALSE;
2231
2232 while (*name) {
2233 if (*name == '/' || g_ascii_isspace (*name))
2234 return FALSE;
2235 name++;
2236 }
2237
2238 return TRUE;
2239 }
2240
2241 /**
2242 * nm_utils_is_uuid:
2243 * @str: a string that might be a UUID
2244 *
2245 * Checks if @str is a UUID
2246 *
2247 * Returns: %TRUE if @str is a UUID, %FALSE if not
2248 *
2249 * Since: 0.9.8
2250 */
2251 gboolean
2252 nm_utils_is_uuid (const char *str)
2253 {
2254 const char *p = str;
2255 int num_dashes = 0;
2256
2257 while (*p) {
2258 if (*p == '-')
2259 num_dashes++;
2260 else if (!g_ascii_isxdigit (*p))
2261 return FALSE;
2262 p++;
2263 }
2264
2265 if ((num_dashes == 4) && (p - str == 36))
2266 return TRUE;
2267
2268 /* Backwards compat for older configurations */
2269 if ((num_dashes == 0) && (p - str == 40))
2270 return TRUE;
2271
2272 return FALSE;
2273 }
2274