1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2 /* NetworkManager system settings service
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program 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
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 *
18 * Copyright (C) 2008 - 2012 Red Hat, Inc.
19 */
20
21 #include <config.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <sys/types.h>
25 #include <sys/socket.h>
26 #include <arpa/inet.h>
27 #include <sys/wait.h>
28 #include <sys/inotify.h>
29 #include <errno.h>
30 #include <sys/ioctl.h>
31 #include <unistd.h>
32 #include <netinet/ether.h>
33 #include <linux/if.h>
34
35 #include <glib.h>
36 #include <glib/gi18n.h>
37 #include <nm-connection.h>
38 #include <NetworkManager.h>
39 #include <nm-setting-connection.h>
40 #include <nm-setting-ip4-config.h>
41 #include <nm-setting-vlan.h>
42 #include <nm-setting-ip6-config.h>
43 #include <nm-setting-wired.h>
44 #include <nm-setting-wireless.h>
45 #include <nm-setting-8021x.h>
46 #include <nm-setting-bond.h>
47 #include <nm-setting-team.h>
48 #include <nm-setting-team-port.h>
49 #include <nm-setting-bridge.h>
50 #include <nm-setting-bridge-port.h>
51 #include <nm-utils.h>
52
53 #include "wifi-utils.h"
54 #include "nm-posix-signals.h"
55 #include "NetworkManagerUtils.h"
56
57 #include "common.h"
58 #include "shvar.h"
59 #include "utils.h"
60
61 #include "reader.h"
62
63 #define PLUGIN_PRINT(pname, fmt, args...) \
64 { g_message (" " pname ": " fmt, ##args); }
65
66 #define PLUGIN_WARN(pname, fmt, args...) \
67 { g_warning (" " pname ": " fmt, ##args); }
68
69 static gboolean
70 get_int (const char *str, int *value)
71 {
72 char *e;
73 long int tmp;
74
75 errno = 0;
76 tmp = strtol (str, &e, 0);
77 if (errno || *e != '\0')
78 return FALSE;
79 *value = (int) tmp;
80 return TRUE;
81 }
82
83 static gboolean
84 get_uint (const char *str, guint32 *value)
85 {
86 char *e;
87 long unsigned int tmp;
88
89 errno = 0;
90 tmp = strtoul (str, &e, 0);
91 if (errno || *e != '\0')
92 return FALSE;
93 *value = (guint32) tmp;
94 return TRUE;
95 }
96
97 static char *
98 make_connection_name (shvarFile *ifcfg,
99 const char *ifcfg_name,
100 const char *suggested,
101 const char *prefix)
102 {
103 char *full_name = NULL, *name;
104
105 /* If the ifcfg file already has a NAME, always use that */
106 name = svGetValue (ifcfg, "NAME", FALSE);
107 if (name && strlen (name))
108 return name;
109
110 /* Otherwise construct a new NAME */
111 g_free (name);
112 if (!prefix)
113 prefix = _("System");
114
115 /* For cosmetic reasons, if the suggested name is the same as
116 * the ifcfg files name, don't use it. Mainly for wifi so that
117 * the SSID is shown in the connection ID instead of just "wlan0".
118 */
119 if (suggested && strcmp (ifcfg_name, suggested))
120 full_name = g_strdup_printf ("%s %s (%s)", prefix, suggested, ifcfg_name);
121 else
122 full_name = g_strdup_printf ("%s %s", prefix, ifcfg_name);
123
124 return full_name;
125 }
126
127 static NMSetting *
128 make_connection_setting (const char *file,
129 shvarFile *ifcfg,
130 const char *type,
131 const char *suggested,
132 const char *prefix)
133 {
134 NMSettingConnection *s_con;
135 const char *ifcfg_name = NULL;
136 char *new_id, *uuid = NULL, *zone = NULL, *value;
137
138 ifcfg_name = utils_get_ifcfg_name (file, TRUE);
139 if (!ifcfg_name)
140 return NULL;
141
142 s_con = NM_SETTING_CONNECTION (nm_setting_connection_new ());
143
144 new_id = make_connection_name (ifcfg, ifcfg_name, suggested, prefix);
145 g_object_set (s_con, NM_SETTING_CONNECTION_ID, new_id, NULL);
146 g_free (new_id);
147
148 /* Try for a UUID key before falling back to hashing the file name */
149 uuid = svGetValue (ifcfg, "UUID", FALSE);
150 if (!uuid || !strlen (uuid)) {
151 g_free (uuid);
152 uuid = nm_utils_uuid_generate_from_string (ifcfg->fileName);
153 }
154
155 g_object_set (s_con,
156 NM_SETTING_CONNECTION_TYPE, type,
157 NM_SETTING_CONNECTION_UUID, uuid,
158 NULL);
159 g_free (uuid);
160
161 value = svGetValue (ifcfg, "DEVICE", FALSE);
162 if (value) {
163 if (nm_utils_iface_valid_name (value)) {
164 g_object_set (s_con,
165 NM_SETTING_CONNECTION_INTERFACE_NAME, value,
166 NULL);
167 } else
168 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: invalid DEVICE name '%s'", value);
169 g_free (value);
170 }
171
172 /* Missing ONBOOT is treated as "ONBOOT=true" by the old network service */
173 g_object_set (s_con, NM_SETTING_CONNECTION_AUTOCONNECT,
174 svTrueValue (ifcfg, "ONBOOT", TRUE),
175 NULL);
176
177 value = svGetValue (ifcfg, "USERS", FALSE);
178 if (value) {
179 char **items, **iter;
180
181 items = g_strsplit_set (value, " ", -1);
182 for (iter = items; iter && *iter; iter++) {
183 if (strlen (*iter)) {
184 if (!nm_setting_connection_add_permission (s_con, "user", *iter, NULL))
185 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: invalid USERS item '%s'", *iter);
186 }
187 }
188 g_free (value);
189 g_strfreev (items);
190 }
191
192
193 zone = svGetValue(ifcfg, "ZONE", FALSE);
194 if (!zone || !strlen (zone)) {
195 g_free (zone);
196 zone = NULL;
197 }
198 g_object_set (s_con, NM_SETTING_CONNECTION_ZONE, zone, NULL);
199 g_free (zone);
200
201 value = svGetValue (ifcfg, "SECONDARY_UUIDS", FALSE);
202 if (value) {
203 char **items, **iter;
204
205 items = g_strsplit_set (value, " \t", -1);
206 for (iter = items; iter && *iter; iter++) {
207 if (strlen (*iter)) {
208 if (!nm_setting_connection_add_secondary (s_con, *iter))
209 PLUGIN_WARN (IFCFG_PLUGIN_NAME,
210 " warning: secondary connection UUID '%s' already added", *iter);
211 }
212 }
213 g_free (value);
214 g_strfreev (items);
215 }
216
217 value = svGetValue (ifcfg, "BRIDGE", FALSE);
218 if (value) {
219 const char *bridge;
220
221 if ((bridge = nm_setting_connection_get_master (s_con))) {
222 PLUGIN_WARN (IFCFG_PLUGIN_NAME,
223 " warning: Already configured as slave of %s. "
224 "Ignoring BRIDGE=\"%s\"", bridge, value);
225 g_free (value);
226 }
227
228 g_object_set (s_con, NM_SETTING_CONNECTION_MASTER, value, NULL);
229 g_object_set (s_con, NM_SETTING_CONNECTION_SLAVE_TYPE,
230 NM_SETTING_BRIDGE_SETTING_NAME, NULL);
231 g_free (value);
232 }
233
234 value = svGetValue (ifcfg, "GATEWAY_PING_TIMEOUT", FALSE);
235 if (value) {
236 long int tmp;
237 guint32 timeout;
238
239 errno = 0;
240 tmp = strtol (value, NULL, 10);
241 if (errno == 0 && tmp >= 0 && tmp < G_MAXINT32) {
242 timeout = (guint32) tmp;
243 g_object_set (s_con, NM_SETTING_CONNECTION_GATEWAY_PING_TIMEOUT, timeout, NULL);
244 } else
245 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: invalid GATEWAY_PING_TIMEOUT time");
246 g_free (value);
247 }
248
249 return NM_SETTING (s_con);
250 }
251
252 static gboolean
253 read_mac_address (shvarFile *ifcfg, const char *key, int type,
254 GByteArray **array, GError **error)
255 {
256 char *value = NULL;
257
258 g_return_val_if_fail (ifcfg != NULL, FALSE);
259 g_return_val_if_fail (array != NULL, FALSE);
260 g_return_val_if_fail (*array == NULL, FALSE);
261 if (error)
262 g_return_val_if_fail (*error == NULL, FALSE);
263
264 value = svGetValue (ifcfg, key, FALSE);
265 if (!value || !strlen (value)) {
266 g_free (value);
267 return TRUE;
268 }
269
270 *array = nm_utils_hwaddr_atoba (value, type);
271 if (!*array) {
272 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
273 "%s: the MAC address '%s' was invalid.", key, value);
274 g_free (value);
275 return FALSE;
276 }
277
278 g_free (value);
279 return TRUE;
280 }
281
282 static void
283 iscsiadm_child_setup (gpointer user_data G_GNUC_UNUSED)
284 {
285 /* We are in the child process here; set a different process group to
286 * ensure signal isolation between child and parent.
287 */
288 pid_t pid = getpid ();
289 setpgid (pid, pid);
290
291 /*
292 * We blocked signals in main(). We need to restore original signal
293 * mask for iscsiadm here so that it can receive signals.
294 */
295 nm_unblock_posix_signals (NULL);
296 }
297
298 static char *
299 match_iscsiadm_tag (const char *line, const char *tag, gboolean *skip)
300 {
301 char *p;
302
303 if (g_ascii_strncasecmp (line, tag, strlen (tag)))
304 return NULL;
305
306 p = strchr (line, '=');
307 if (!p) {
308 g_warning ("%s: malformed iscsiadm record: no = in '%s'.",
309 __func__, line);
310 *skip = TRUE;
311 return NULL;
312 }
313
314 p++; /* advance past = */
315 return g_strstrip (p);
316 }
317
318 #define ISCSI_HWADDR_TAG "iface.hwaddress"
319 #define ISCSI_BOOTPROTO_TAG "iface.bootproto"
320 #define ISCSI_IPADDR_TAG "iface.ipaddress"
321 #define ISCSI_SUBNET_TAG "iface.subnet_mask"
322 #define ISCSI_GATEWAY_TAG "iface.gateway"
323 #define ISCSI_DNS1_TAG "iface.primary_dns"
324 #define ISCSI_DNS2_TAG "iface.secondary_dns"
325
326 static gboolean
327 fill_ip4_setting_from_ibft (shvarFile *ifcfg,
328 NMSettingIP4Config *s_ip4,
329 const char *iscsiadm_path,
330 GError **error)
331 {
332 const char *argv[4] = { iscsiadm_path, "-m", "fw", NULL };
333 const char *envp[1] = { NULL };
334 gboolean success = FALSE, in_record = FALSE, hwaddr_matched = FALSE, skip = FALSE;
335 char *out = NULL, *err = NULL;
336 gint status = 0;
337 GByteArray *ifcfg_mac = NULL;
338 char **lines = NULL, **iter;
339 const char *method = NULL;
340 guint32 ipaddr;
341 guint32 gateway;
342 guint32 dns1;
343 guint32 dns2;
344 guint32 prefix = 0;
345
346 g_return_val_if_fail (s_ip4 != NULL, FALSE);
347 g_return_val_if_fail (iscsiadm_path != NULL, FALSE);
348
349 if (!g_spawn_sync ("/", (char **) argv, (char **) envp, 0,
350 iscsiadm_child_setup, NULL, &out, &err, &status, error))
351 return FALSE;
352
353 if (!WIFEXITED (status)) {
354 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
355 "%s exited abnormally.", iscsiadm_path);
356 goto done;
357 }
358
359 if (WEXITSTATUS (status) != 0) {
360 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
361 "%s exited with error %d. Message: '%s'",
362 iscsiadm_path, WEXITSTATUS (status), err ? err : "(none)");
363 goto done;
364 }
365
366 if (!read_mac_address (ifcfg, "HWADDR", ARPHRD_ETHER, &ifcfg_mac, error))
367 goto done;
368 /* Ensure we got a MAC */
369 if (!ifcfg_mac) {
370 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
371 "Missing device MAC address (no HWADDR tag present).");
372 goto done;
373 }
374
375 memset (&ipaddr, 0, sizeof (ipaddr));
376 memset (&gateway, 0, sizeof (gateway));
377 memset (&dns1, 0, sizeof (dns1));
378 memset (&dns2, 0, sizeof (dns2));
379
380 /* Success, lets parse the output */
381 lines = g_strsplit_set (out, "\n\r", -1);
382 for (iter = lines; iter && *iter; iter++) {
383 char *p;
384
385 if (!g_ascii_strcasecmp (*iter, "# BEGIN RECORD")) {
386 if (in_record) {
387 g_warning ("%s: malformed iscsiadm record: already parsing record.", __func__);
388 skip = TRUE;
389 }
390 } else if (!g_ascii_strcasecmp (*iter, "# END RECORD")) {
391 if (!skip && hwaddr_matched) {
392 /* Record is good; fill IP4 config with its info */
393 if (!method) {
394 g_warning ("%s: malformed iscsiadm record: missing BOOTPROTO.", __func__);
395 goto done;
396 }
397
398 g_object_set (s_ip4, NM_SETTING_IP4_CONFIG_METHOD, method, NULL);
399
400 if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) {
401 NMIP4Address *addr;
402
403 if (!ipaddr || !prefix) {
404 g_warning ("%s: malformed iscsiadm record: BOOTPROTO=static "
405 "but missing IP address or prefix.", __func__);
406 goto done;
407 }
408
409 addr = nm_ip4_address_new ();
410 nm_ip4_address_set_address (addr, ipaddr);
411 nm_ip4_address_set_prefix (addr, prefix);
412 nm_ip4_address_set_gateway (addr, gateway);
413 nm_setting_ip4_config_add_address (s_ip4, addr);
414 nm_ip4_address_unref (addr);
415
416 if (dns1)
417 nm_setting_ip4_config_add_dns (s_ip4, dns1);
418 if (dns2)
419 nm_setting_ip4_config_add_dns (s_ip4, dns2);
420
421 // FIXME: DNS search domains?
422 }
423 success = TRUE;
424 goto done;
425 }
426 skip = FALSE;
427 hwaddr_matched = FALSE;
428 memset (&ipaddr, 0, sizeof (ipaddr));
429 memset (&gateway, 0, sizeof (gateway));
430 memset (&dns1, 0, sizeof (dns1));
431 memset (&dns2, 0, sizeof (dns2));
432 prefix = 0;
433 method = NULL;
434 }
435
436 if (skip)
437 continue;
438
439 /* HWADDR */
440 if (!skip && (p = match_iscsiadm_tag (*iter, ISCSI_HWADDR_TAG, &skip))) {
441 struct ether_addr *ibft_mac;
442
443 ibft_mac = ether_aton (p);
444 if (!ibft_mac) {
445 g_warning ("%s: malformed iscsiadm record: invalid hwaddress.", __func__);
446 skip = TRUE;
447 continue;
448 }
449
450 if (memcmp (ifcfg_mac->data, (guint8 *) ibft_mac->ether_addr_octet, ETH_ALEN)) {
451 /* This record isn't for the current device, ignore it */
452 skip = TRUE;
453 continue;
454 }
455
456 /* Success, this record is for this device */
457 hwaddr_matched = TRUE;
458 }
459
460 /* BOOTPROTO */
461 if (!skip && (p = match_iscsiadm_tag (*iter, ISCSI_BOOTPROTO_TAG, &skip))) {
462 if (!g_ascii_strcasecmp (p, "dhcp"))
463 method = NM_SETTING_IP4_CONFIG_METHOD_AUTO;
464 else if (!g_ascii_strcasecmp (p, "static"))
465 method = NM_SETTING_IP4_CONFIG_METHOD_MANUAL;
466 else {
467 g_warning ("%s: malformed iscsiadm record: unknown BOOTPROTO '%s'.",
468 __func__, p);
469 skip = TRUE;
470 continue;
471 }
472 }
473
474 if (!skip && (p = match_iscsiadm_tag (*iter, ISCSI_IPADDR_TAG, &skip))) {
475 if (inet_pton (AF_INET, p, &ipaddr) < 1) {
476 g_warning ("%s: malformed iscsiadm record: invalid IP address '%s'.",
477 __func__, p);
478 skip = TRUE;
479 continue;
480 }
481 }
482
483 if (!skip && (p = match_iscsiadm_tag (*iter, ISCSI_SUBNET_TAG, &skip))) {
484 guint32 mask;
485
486 if (inet_pton (AF_INET, p, &mask) < 1) {
487 g_warning ("%s: malformed iscsiadm record: invalid subnet mask '%s'.",
488 __func__, p);
489 skip = TRUE;
490 continue;
491 }
492
493 prefix = nm_utils_ip4_netmask_to_prefix (mask);
494 }
495
496 if (!skip && (p = match_iscsiadm_tag (*iter, ISCSI_GATEWAY_TAG, &skip))) {
497 if (inet_pton (AF_INET, p, &gateway) < 1) {
498 g_warning ("%s: malformed iscsiadm record: invalid IP gateway '%s'.",
499 __func__, p);
500 skip = TRUE;
501 continue;
502 }
503 }
504
505 if (!skip && (p = match_iscsiadm_tag (*iter, ISCSI_DNS1_TAG, &skip))) {
506 if (inet_pton (AF_INET, p, &dns1) < 1) {
507 g_warning ("%s: malformed iscsiadm record: invalid DNS1 address '%s'.",
508 __func__, p);
509 skip = TRUE;
510 continue;
511 }
512 }
513
514 if (!skip && (p = match_iscsiadm_tag (*iter, ISCSI_DNS2_TAG, &skip))) {
515 if (inet_pton (AF_INET, p, &dns2) < 1) {
516 g_warning ("%s: malformed iscsiadm record: invalid DNS2 address '%s'.",
517 __func__, p);
518 skip = TRUE;
519 continue;
520 }
521 }
522 }
523
524 success = TRUE;
525
526 done:
527 if (ifcfg_mac)
528 g_byte_array_free (ifcfg_mac, TRUE);
529 g_strfreev (lines);
530 g_free (out);
531 g_free (err);
532 return success;
533 }
534
535 /* Returns TRUE on missing address or valid address */
536 static gboolean
537 read_ip4_address (shvarFile *ifcfg,
538 const char *tag,
539 guint32 *out_addr,
540 GError **error)
541 {
542 char *value = NULL;
543 guint32 ip4_addr;
544 gboolean success = FALSE;
545
546 g_return_val_if_fail (ifcfg != NULL, FALSE);
547 g_return_val_if_fail (tag != NULL, FALSE);
548 g_return_val_if_fail (out_addr != NULL, FALSE);
549 if (error)
550 g_return_val_if_fail (*error == NULL, FALSE);
551
552 *out_addr = 0;
553
554 value = svGetValue (ifcfg, tag, FALSE);
555 if (!value)
556 return TRUE;
557
558 if (inet_pton (AF_INET, value, &ip4_addr) > 0) {
559 *out_addr = ip4_addr;
560 success = TRUE;
561 } else {
562 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
563 "Invalid %s IP4 address '%s'", tag, value);
564 }
565 g_free (value);
566 return success;
567 }
568
569 /* Returns TRUE on valid address, including unspecified (::) */
570 static gboolean
571 parse_ip6_address (const char *value,
572 struct in6_addr *out_addr,
573 GError **error)
574 {
575 struct in6_addr ip6_addr;
576
577 g_return_val_if_fail (value != NULL, FALSE);
578 g_return_val_if_fail (out_addr != NULL, FALSE);
579 if (error)
580 g_return_val_if_fail (*error == NULL, FALSE);
581
582 *out_addr = in6addr_any;
583 if (inet_pton (AF_INET6, value, &ip6_addr) <= 0) {
584 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
585 "Invalid IP6 address '%s'", value);
586 return FALSE;
587 }
588
589 *out_addr = ip6_addr;
590 return TRUE;
591 }
592
593 static char *
594 get_numbered_tag (char *tag_name, int which)
595 {
596 if (which == -1)
597 return g_strdup (tag_name);
598 return g_strdup_printf ("%s%u", tag_name, which);
599 }
600
601 static gboolean
602 is_any_ip4_address_defined (shvarFile *ifcfg)
603 {
604 int i;
605
606 for (i = -1; i <= 2; i++) {
607 char *tag;
608 char *value;
609
610 tag = get_numbered_tag ("IPADDR", i);
611 value = svGetValue (ifcfg, tag, FALSE);
612 g_free (tag);
613 if (value) {
614 g_free (value);
615 return TRUE;
616 }
617
618 tag = get_numbered_tag ("PREFIX", i);
619 value = svGetValue (ifcfg, tag, FALSE);
620 g_free(tag);
621 if (value) {
622 g_free (value);
623 return TRUE;
624 }
625
626 tag = get_numbered_tag ("NETMASK", i);
627 value = svGetValue (ifcfg, tag, FALSE);
628 g_free(tag);
629 if (value) {
630 g_free (value);
631 return TRUE;
632 }
633 }
634 return FALSE;
635 }
636
637 /* Returns TRUE on missing address or valid address */
638 static gboolean
639 read_full_ip4_address (shvarFile *ifcfg,
640 const char *network_file,
641 gint32 which,
642 NMIP4Address **out_address,
643 GError **error)
644 {
645 NMIP4Address *addr;
646 char *ip_tag, *prefix_tag, *netmask_tag, *gw_tag;
647 guint32 tmp;
648 gboolean success = FALSE;
649 shvarFile *network_ifcfg;
650 char *value;
651
652 g_return_val_if_fail (which >= -1, FALSE);
653 g_return_val_if_fail (ifcfg != NULL, FALSE);
654 g_return_val_if_fail (network_file != NULL, FALSE);
655 g_return_val_if_fail (out_address != NULL, FALSE);
656 g_return_val_if_fail (*out_address == NULL, FALSE);
657 if (error)
658 g_return_val_if_fail (*error == NULL, FALSE);
659
660 addr = nm_ip4_address_new ();
661 ip_tag = get_numbered_tag ("IPADDR", which);
662 prefix_tag = get_numbered_tag ("PREFIX", which);
663 netmask_tag = get_numbered_tag ("NETMASK", which);
664 gw_tag = get_numbered_tag ("GATEWAY", which);
665
666 /* IP address */
667 if (!read_ip4_address (ifcfg, ip_tag, &tmp, error))
668 goto done;
669 if (!tmp) {
670 nm_ip4_address_unref (addr);
671 addr = NULL;
672 success = TRUE; /* done */
673 goto done;
674 }
675 nm_ip4_address_set_address (addr, tmp);
676
677 /* Gateway */
678 if (!read_ip4_address (ifcfg, gw_tag, &tmp, error))
679 goto done;
680 if (tmp)
681 nm_ip4_address_set_gateway (addr, tmp);
682 else {
683 gboolean read_success;
684
685 /* If no gateway in the ifcfg, try /etc/sysconfig/network instead */
686 network_ifcfg = svNewFile (network_file);
687 if (network_ifcfg) {
688 read_success = read_ip4_address (network_ifcfg, "GATEWAY", &tmp, error);
689 svCloseFile (network_ifcfg);
690 if (!read_success)
691 goto done;
692 nm_ip4_address_set_gateway (addr, tmp);
693 }
694 }
695
696 /* Prefix */
697 value = svGetValue (ifcfg, prefix_tag, FALSE);
698 if (value) {
699 long int prefix;
700
701 errno = 0;
702 prefix = strtol (value, NULL, 10);
703 if (errno || prefix <= 0 || prefix > 32) {
704 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
705 "Invalid IP4 prefix '%s'", value);
706 g_free (value);
707 goto done;
708 }
709 nm_ip4_address_set_prefix (addr, (guint32) prefix);
710 g_free (value);
711 }
712
713 /* Fall back to NETMASK if no PREFIX was specified */
714 if (!nm_ip4_address_get_prefix (addr)) {
715 if (!read_ip4_address (ifcfg, netmask_tag, &tmp, error))
716 goto done;
717 if (tmp)
718 nm_ip4_address_set_prefix (addr, nm_utils_ip4_netmask_to_prefix (tmp));
719 }
720
721 /* Try to autodetermine the prefix for the address' class */
722 if (!nm_ip4_address_get_prefix (addr)) {
723 guint32 prefix = 0;
724
725 prefix = nm_utils_ip4_get_default_prefix (nm_ip4_address_get_address (addr));
726 nm_ip4_address_set_prefix (addr, prefix);
727
728 value = svGetValue (ifcfg, ip_tag, FALSE);
729 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: missing %s, assuming %s/%u",
730 prefix_tag, value, prefix);
731 g_free (value);
732 }
733
734 /* Validate the prefix */
735 if (nm_ip4_address_get_prefix (addr) > 32) {
736 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
737 "Missing or invalid IP4 prefix '%d'",
738 nm_ip4_address_get_prefix (addr));
739 goto done;
740 }
741
742 *out_address = addr;
743 success = TRUE;
744
745 done:
746 if (!success && addr)
747 nm_ip4_address_unref (addr);
748
749 g_free (ip_tag);
750 g_free (prefix_tag);
751 g_free (netmask_tag);
752 g_free (gw_tag);
753
754 return success;
755 }
756
757 /* Returns TRUE on missing route or valid route */
758 static gboolean
759 read_one_ip4_route (shvarFile *ifcfg,
760 const char *network_file,
761 guint32 which,
762 NMIP4Route **out_route,
763 GError **error)
764 {
765 NMIP4Route *route;
766 char *ip_tag, *netmask_tag, *gw_tag, *metric_tag, *value;
767 guint32 tmp;
768 gboolean success = FALSE;
769
770 g_return_val_if_fail (ifcfg != NULL, FALSE);
771 g_return_val_if_fail (network_file != NULL, FALSE);
772 g_return_val_if_fail (out_route != NULL, FALSE);
773 g_return_val_if_fail (*out_route == NULL, FALSE);
774 if (error)
775 g_return_val_if_fail (*error == NULL, FALSE);
776
777 route = nm_ip4_route_new ();
778
779 ip_tag = g_strdup_printf ("ADDRESS%u", which);
780 netmask_tag = g_strdup_printf ("NETMASK%u", which);
781 gw_tag = g_strdup_printf ("GATEWAY%u", which);
782 metric_tag = g_strdup_printf ("METRIC%u", which);
783
784 /* Destination */
785 if (!read_ip4_address (ifcfg, ip_tag, &tmp, error))
786 goto out;
787 if (!tmp) {
788 /* Check whether IP is missing or 0.0.0.0 */
789 char *val;
790 val = svGetValue (ifcfg, ip_tag, FALSE);
791 if (!val) {
792 nm_ip4_route_unref (route);
793 route = NULL;
794 success = TRUE; /* missing route = success */
795 goto out;
796 }
797 g_free (val);
798 }
799 nm_ip4_route_set_dest (route, tmp);
800
801 /* Next hop */
802 if (!read_ip4_address (ifcfg, gw_tag, &tmp, error))
803 goto out;
804 /* No need to check tmp, because we don't make distinction between missing GATEWAY IP and 0.0.0.0 */
805 nm_ip4_route_set_next_hop (route, tmp);
806
807 /* Prefix */
808 if (!read_ip4_address (ifcfg, netmask_tag, &tmp, error))
809 goto out;
810 if (tmp)
811 nm_ip4_route_set_prefix (route, nm_utils_ip4_netmask_to_prefix (tmp));
812
813 /* Validate the prefix */
814 if ( !nm_ip4_route_get_prefix (route)
815 || nm_ip4_route_get_prefix (route) > 32) {
816 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
817 "Missing or invalid IP4 prefix '%d'",
818 nm_ip4_route_get_prefix (route));
819 goto out;
820 }
821
822 /* Metric */
823 value = svGetValue (ifcfg, metric_tag, FALSE);
824 if (value) {
825 long int metric;
826
827 errno = 0;
828 metric = strtol (value, NULL, 10);
829 if (errno || metric < 0) {
830 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
831 "Invalid IP4 route metric '%s'", value);
832 g_free (value);
833 goto out;
834 }
835 nm_ip4_route_set_metric (route, (guint32) metric);
836 g_free (value);
837 }
838
839 *out_route = route;
840 success = TRUE;
841
842 out:
843 if (!success && route)
844 nm_ip4_route_unref (route);
845
846 g_free (ip_tag);
847 g_free (netmask_tag);
848 g_free (gw_tag);
849 g_free (metric_tag);
850 return success;
851 }
852
853 static gboolean
854 read_route_file_legacy (const char *filename, NMSettingIP4Config *s_ip4, GError **error)
855 {
856 char *contents = NULL;
857 gsize len = 0;
858 char **lines = NULL, **iter;
859 GRegex *regex_to1, *regex_to2, *regex_via, *regex_metric;
860 GMatchInfo *match_info;
861 NMIP4Route *route;
862 guint32 ip4_addr;
863 char *dest = NULL, *prefix = NULL, *metric = NULL;
864 long int prefix_int, metric_int;
865 gboolean success = FALSE;
866
867 const char *pattern_empty = "^\\s*(\\#.*)?$";
868 const char *pattern_to1 = "^\\s*(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}|default)" /* IP or 'default' keyword */
869 "(?:/(\\d{1,2}))?"; /* optional prefix */
870 const char *pattern_to2 = "to\\s+(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}|default)" /* IP or 'default' keyword */
871 "(?:/(\\d{1,2}))?"; /* optional prefix */
872 const char *pattern_via = "via\\s+(\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})"; /* IP of gateway */
873 const char *pattern_metric = "metric\\s+(\\d+)"; /* metric */
874
875 g_return_val_if_fail (filename != NULL, FALSE);
876 g_return_val_if_fail (s_ip4 != NULL, FALSE);
877 if (error)
878 g_return_val_if_fail (*error == NULL, FALSE);
879
880 /* Read the route file */
881 if (!g_file_get_contents (filename, &contents, &len, NULL) || !len) {
882 g_free (contents);
883 return TRUE; /* missing/empty = success */
884 }
885
886 /* Create regexes for pieces to be matched */
887 regex_to1 = g_regex_new (pattern_to1, 0, 0, NULL);
888 regex_to2 = g_regex_new (pattern_to2, 0, 0, NULL);
889 regex_via = g_regex_new (pattern_via, 0, 0, NULL);
890 regex_metric = g_regex_new (pattern_metric, 0, 0, NULL);
891
892 /* New NMIP4Route structure */
893 route = nm_ip4_route_new ();
894
895 /* Iterate through file lines */
896 lines = g_strsplit_set (contents, "\n\r", -1);
897 for (iter = lines; iter && *iter; iter++) {
898
899 /* Skip empty lines */
900 if (g_regex_match_simple (pattern_empty, *iter, 0, 0))
901 continue;
902
903 /* Destination */
904 g_regex_match (regex_to1, *iter, 0, &match_info);
905 if (!g_match_info_matches (match_info)) {
906 g_match_info_free (match_info);
907 g_regex_match (regex_to2, *iter, 0, &match_info);
908 if (!g_match_info_matches (match_info)) {
909 g_match_info_free (match_info);
910 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
911 "Missing IP4 route destination address in record: '%s'", *iter);
912 goto error;
913 }
914 }
915 dest = g_match_info_fetch (match_info, 1);
916 if (!strcmp (dest, "default"))
917 strcpy (dest, "0.0.0.0");
918 if (inet_pton (AF_INET, dest, &ip4_addr) != 1) {
919 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
920 "Invalid IP4 route destination address '%s'", dest);
921 g_free (dest);
922 goto error;
923 }
924 nm_ip4_route_set_dest (route, ip4_addr);
925 g_free (dest);
926
927 /* Prefix - is optional; 32 if missing */
928 prefix = g_match_info_fetch (match_info, 2);
929 g_match_info_free (match_info);
930 prefix_int = 32;
931 if (prefix) {
932 errno = 0;
933 prefix_int = strtol (prefix, NULL, 10);
934 if (errno || prefix_int <= 0 || prefix_int > 32) {
935 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
936 "Invalid IP4 route destination prefix '%s'", prefix);
937 g_free (prefix);
938 goto error;
939 }
940 }
941 nm_ip4_route_set_prefix (route, (guint32) prefix_int);
942 g_free (prefix);
943
944 /* Next hop */
945 g_regex_match (regex_via, *iter, 0, &match_info);
946 if (g_match_info_matches (match_info)) {
947 char *next_hop = g_match_info_fetch (match_info, 1);
948 if (inet_pton (AF_INET, next_hop, &ip4_addr) != 1) {
949 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
950 "Invalid IP4 route gateway address '%s'",
951 next_hop);
952 g_match_info_free (match_info);
953 g_free (next_hop);
954 goto error;
955 }
956 g_free (next_hop);
957 } else {
958 /* we don't make distinction between missing GATEWAY IP and 0.0.0.0 */
959 ip4_addr = 0;
960 }
961 nm_ip4_route_set_next_hop (route, ip4_addr);
962 g_match_info_free (match_info);
963
964 /* Metric */
965 g_regex_match (regex_metric, *iter, 0, &match_info);
966 metric_int = 0;
967 if (g_match_info_matches (match_info)) {
968 metric = g_match_info_fetch (match_info, 1);
969 errno = 0;
970 metric_int = strtol (metric, NULL, 10);
971 if (errno || metric_int < 0) {
972 g_match_info_free (match_info);
973 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
974 "Invalid IP4 route metric '%s'", metric);
975 g_free (metric);
976 goto error;
977 }
978 g_free (metric);
979 }
980
981 nm_ip4_route_set_metric (route, (guint32) metric_int);
982 g_match_info_free (match_info);
983
984 if (!nm_setting_ip4_config_add_route (s_ip4, route))
985 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: duplicate IP4 route");
986
987 }
988
989 success = TRUE;
990
991 error:
992 g_free (contents);
993 g_strfreev (lines);
994 nm_ip4_route_unref (route);
995 g_regex_unref (regex_to1);
996 g_regex_unref (regex_to2);
997 g_regex_unref (regex_via);
998 g_regex_unref (regex_metric);
999
1000 return success;
1001 }
1002
1003 static gboolean
1004 parse_full_ip6_address (shvarFile *ifcfg,
1005 const char *network_file,
1006 const char *addr_str,
1007 int i,
1008 NMIP6Address **out_address,
1009 GError **error)
1010 {
1011 NMIP6Address *addr = NULL;
1012 char **list;
1013 char *ip_val, *prefix_val;
1014 shvarFile *network_ifcfg;
1015 char *value = NULL;
1016 struct in6_addr tmp = IN6ADDR_ANY_INIT;
1017 gboolean success = FALSE;
1018
1019 g_return_val_if_fail (addr_str != NULL, FALSE);
1020 g_return_val_if_fail (out_address != NULL, FALSE);
1021 g_return_val_if_fail (*out_address == NULL, FALSE);
1022 if (error)
1023 g_return_val_if_fail (*error == NULL, FALSE);
1024
1025 /* Split the address and prefix */
1026 list = g_strsplit_set (addr_str, "/", 2);
1027 if (g_strv_length (list) < 1) {
1028 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
1029 "Invalid IP6 address '%s'", addr_str);
1030 goto error;
1031 }
1032
1033 ip_val = list[0];
1034 prefix_val = list[1];
1035
1036 addr = nm_ip6_address_new ();
1037 /* IP address */
1038 if (!parse_ip6_address (ip_val, &tmp, error))
1039 goto error;
1040 if (IN6_IS_ADDR_UNSPECIFIED (&tmp)) {
1041 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
1042 "Invalid IP6 address '%s'", ip_val);
1043 goto error;
1044 }
1045 nm_ip6_address_set_address (addr, &tmp);
1046
1047 /* Prefix */
1048 if (prefix_val) {
1049 long int prefix;
1050
1051 errno = 0;
1052 prefix = strtol (prefix_val, NULL, 10);
1053 if (errno || prefix <= 0 || prefix > 128) {
1054 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
1055 "Invalid IP6 prefix '%s'", prefix_val);
1056 goto error;
1057 }
1058 nm_ip6_address_set_prefix (addr, (guint32) prefix);
1059 } else {
1060 /* Missing prefix is treated as prefix of 64 */
1061 nm_ip6_address_set_prefix (addr, 64);
1062 }
1063
1064 /* Gateway */
1065 tmp = in6addr_any;
1066 value = svGetValue (ifcfg, "IPV6_DEFAULTGW", FALSE);
1067 if (i != 0) {
1068 /* We don't support gateways for IPV6ADDR_SECONDARIES yet */
1069 g_free (value);
1070 value = NULL;
1071 }
1072 if (!value) {
1073 /* If no gateway in the ifcfg, try global /etc/sysconfig/network instead */
1074 network_ifcfg = svNewFile (network_file);
1075 if (network_ifcfg) {
1076 value = svGetValue (network_ifcfg, "IPV6_DEFAULTGW", FALSE);
1077 svCloseFile (network_ifcfg);
1078 }
1079 }
1080 if (value) {
1081 char *ptr;
1082
1083 if ((ptr = strchr (value, '%')) != NULL)
1084 *ptr = '\0'; /* remove %interface prefix if present */
1085 if (!parse_ip6_address (value, &tmp, error))
1086 goto error;
1087 nm_ip6_address_set_gateway (addr, &tmp);
1088 }
1089
1090 *out_address = addr;
1091 success = TRUE;
1092
1093 error:
1094 if (!success && addr)
1095 nm_ip6_address_unref (addr);
1096
1097 g_strfreev (list);
1098 g_free (value);
1099 return success;
1100 }
1101
1102 /* IPv6 address is very complex to describe completely by a regular expression,
1103 * so don't try to, rather use looser syntax to comprise all possibilities
1104 * NOTE: The regexes below don't describe all variants allowed by 'ip route add',
1105 * namely destination IP without 'to' keyword is recognized just at line start.
1106 */
1107 #define IPV6_ADDR_REGEX "[0-9A-Fa-f:.]+"
1108
1109 static gboolean
1110 read_route6_file (const char *filename, NMSettingIP6Config *s_ip6, GError **error)
1111 {
1112 char *contents = NULL;
1113 gsize len = 0;
1114 char **lines = NULL, **iter;
1115 GRegex *regex_to1, *regex_to2, *regex_via, *regex_metric;
1116 GMatchInfo *match_info;
1117 NMIP6Route *route;
1118 struct in6_addr ip6_addr;
1119 char *dest = NULL, *prefix = NULL, *next_hop = NULL, *metric = NULL;
1120 long int prefix_int, metric_int;
1121 gboolean success = FALSE;
1122
1123 const char *pattern_empty = "^\\s*(\\#.*)?$";
1124 const char *pattern_to1 = "^\\s*(default|" IPV6_ADDR_REGEX ")" /* IPv6 or 'default' keyword */
1125 "(?:/(\\d{1,3}))?"; /* optional prefix */
1126 const char *pattern_to2 = "to\\s+(default|" IPV6_ADDR_REGEX ")" /* IPv6 or 'default' keyword */
1127 "(?:/(\\d{1,3}))?"; /* optional prefix */
1128 const char *pattern_via = "via\\s+(" IPV6_ADDR_REGEX ")"; /* IPv6 of gateway */
1129 const char *pattern_metric = "metric\\s+(\\d+)"; /* metric */
1130
1131 g_return_val_if_fail (filename != NULL, FALSE);
1132 g_return_val_if_fail (s_ip6 != NULL, FALSE);
1133 if (error)
1134 g_return_val_if_fail (*error == NULL, FALSE);
1135
1136 /* Read the route file */
1137 if (!g_file_get_contents (filename, &contents, &len, NULL) || !len) {
1138 g_free (contents);
1139 return TRUE; /* missing/empty = success */
1140 }
1141
1142 /* Create regexes for pieces to be matched */
1143 regex_to1 = g_regex_new (pattern_to1, 0, 0, NULL);
1144 regex_to2 = g_regex_new (pattern_to2, 0, 0, NULL);
1145 regex_via = g_regex_new (pattern_via, 0, 0, NULL);
1146 regex_metric = g_regex_new (pattern_metric, 0, 0, NULL);
1147
1148 /* New NMIP6Route structure */
1149 route = nm_ip6_route_new ();
1150
1151 /* Iterate through file lines */
1152 lines = g_strsplit_set (contents, "\n\r", -1);
1153 for (iter = lines; iter && *iter; iter++) {
1154
1155 /* Skip empty lines */
1156 if (g_regex_match_simple (pattern_empty, *iter, 0, 0))
1157 continue;
1158
1159 /* Destination */
1160 g_regex_match (regex_to1, *iter, 0, &match_info);
1161 if (!g_match_info_matches (match_info)) {
1162 g_match_info_free (match_info);
1163 g_regex_match (regex_to2, *iter, 0, &match_info);
1164 if (!g_match_info_matches (match_info)) {
1165 g_match_info_free (match_info);
1166 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
1167 "Missing IP6 route destination address in record: '%s'", *iter);
1168 goto error;
1169 }
1170 }
1171 dest = g_match_info_fetch (match_info, 1);
1172 if (!g_strcmp0 (dest, "default")) {
1173 /* Ignore default route - NM handles it internally */
1174 g_free (dest);
1175 g_match_info_free (match_info);
1176 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: ignoring manual default route: '%s' (%s)",
1177 *iter, filename);
1178 continue;
1179 }
1180 if (inet_pton (AF_INET6, dest, &ip6_addr) != 1) {
1181 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
1182 "Invalid IP6 route destination address '%s'", dest);
1183 g_free (dest);
1184 goto error;
1185 }
1186 nm_ip6_route_set_dest (route, &ip6_addr);
1187 g_free (dest);
1188
1189 /* Prefix - is optional; 128 if missing */
1190 prefix = g_match_info_fetch (match_info, 2);
1191 g_match_info_free (match_info);
1192 prefix_int = 128;
1193 if (prefix) {
1194 errno = 0;
1195 prefix_int = strtol (prefix, NULL, 10);
1196 if (errno || prefix_int <= 0 || prefix_int > 128) {
1197 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
1198 "Invalid IP6 route destination prefix '%s'", prefix);
1199 g_free (prefix);
1200 goto error;
1201 }
1202 }
1203 nm_ip6_route_set_prefix (route, (guint32) prefix_int);
1204 g_free (prefix);
1205
1206 /* Next hop */
1207 g_regex_match (regex_via, *iter, 0, &match_info);
1208 if (!g_match_info_matches (match_info)) {
1209 g_match_info_free (match_info);
1210 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
1211 "Missing IP6 route gateway address in record: '%s'", *iter);
1212 goto error;
1213 }
1214 next_hop = g_match_info_fetch (match_info, 1);
1215 g_match_info_free (match_info);
1216 if (inet_pton (AF_INET6, next_hop, &ip6_addr) != 1) {
1217 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
1218 "Invalid IP6 route gateway address '%s'", next_hop);
1219 g_free (next_hop);
1220 goto error;
1221 }
1222 nm_ip6_route_set_next_hop (route, &ip6_addr);
1223 g_free (next_hop);
1224
1225 /* Metric */
1226 g_regex_match (regex_metric, *iter, 0, &match_info);
1227 metric_int = 0;
1228 if (g_match_info_matches (match_info)) {
1229 metric = g_match_info_fetch (match_info, 1);
1230 errno = 0;
1231 metric_int = strtol (metric, NULL, 10);
1232 if (errno || metric_int < 0 || metric_int > G_MAXUINT32) {
1233 g_match_info_free (match_info);
1234 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
1235 "Invalid IP6 route metric '%s'", metric);
1236 g_free (metric);
1237 goto error;
1238 }
1239 g_free (metric);
1240 }
1241
1242 nm_ip6_route_set_metric (route, (guint32) metric_int);
1243 g_match_info_free (match_info);
1244
1245 if (!nm_setting_ip6_config_add_route (s_ip6, route))
1246 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: duplicate IP6 route");
1247 }
1248
1249 success = TRUE;
1250
1251 error:
1252 g_free (contents);
1253 g_strfreev (lines);
1254 nm_ip6_route_unref (route);
1255 g_regex_unref (regex_to1);
1256 g_regex_unref (regex_to2);
1257 g_regex_unref (regex_via);
1258 g_regex_unref (regex_metric);
1259
1260 return success;
1261 }
1262
1263
1264 static NMSetting *
1265 make_ip4_setting (shvarFile *ifcfg,
1266 const char *network_file,
1267 const char *iscsiadm_path,
1268 GError **error)
1269 {
1270 NMSettingIP4Config *s_ip4 = NULL;
1271 char *value = NULL;
1272 char *route_path = NULL;
1273 char *method;
1274 gint32 i;
1275 shvarFile *network_ifcfg;
1276 shvarFile *route_ifcfg;
1277 gboolean never_default = FALSE;
1278
1279 s_ip4 = (NMSettingIP4Config *) nm_setting_ip4_config_new ();
1280
1281 /* First check if DEFROUTE is set for this device; DEFROUTE has the
1282 * opposite meaning from never-default. The default if DEFROUTE is not
1283 * specified is DEFROUTE=yes which means that this connection can be used
1284 * as a default route
1285 */
1286 never_default = !svTrueValue (ifcfg, "DEFROUTE", TRUE);
1287
1288 /* Then check if GATEWAYDEV; it's global and overrides DEFROUTE */
1289 network_ifcfg = svNewFile (network_file);
1290 if (network_ifcfg) {
1291 char *gatewaydev;
1292
1293 /* Get the connection ifcfg device name and the global gateway device */
1294 value = svGetValue (ifcfg, "DEVICE", FALSE);
1295 gatewaydev = svGetValue (network_ifcfg, "GATEWAYDEV", FALSE);
1296
1297 /* If there was a global gateway device specified, then only connections
1298 * for that device can be the default connection.
1299 */
1300 if (gatewaydev && value)
1301 never_default = !!strcmp (value, gatewaydev);
1302
1303 g_free (gatewaydev);
1304 g_free (value);
1305 svCloseFile (network_ifcfg);
1306 }
1307
1308 value = svGetValue (ifcfg, "BOOTPROTO", FALSE);
1309
1310 if (!value || !*value || !g_ascii_strcasecmp (value, "none")) {
1311 if (is_any_ip4_address_defined (ifcfg))
1312 method = NM_SETTING_IP4_CONFIG_METHOD_MANUAL;
1313 else
1314 method = NM_SETTING_IP4_CONFIG_METHOD_DISABLED;
1315 } else if (!g_ascii_strcasecmp (value, "bootp") || !g_ascii_strcasecmp (value, "dhcp")) {
1316 method = NM_SETTING_IP4_CONFIG_METHOD_AUTO;
1317 } else if (!g_ascii_strcasecmp (value, "static")) {
1318 method = NM_SETTING_IP4_CONFIG_METHOD_MANUAL;
1319 } else if (!g_ascii_strcasecmp (value, "ibft")) {
1320 g_free (value);
1321 g_object_set (s_ip4, NM_SETTING_IP4_CONFIG_NEVER_DEFAULT, never_default, NULL);
1322 /* iSCSI Boot Firmware Table: need to read values from the iSCSI
1323 * firmware for this device and create the IP4 setting using those.
1324 */
1325 if (fill_ip4_setting_from_ibft (ifcfg, s_ip4, iscsiadm_path, error))
1326 return NM_SETTING (s_ip4);
1327 g_object_unref (s_ip4);
1328 return NULL;
1329 } else if (!g_ascii_strcasecmp (value, "autoip")) {
1330 g_free (value);
1331 g_object_set (s_ip4,
1332 NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL,
1333 NM_SETTING_IP4_CONFIG_NEVER_DEFAULT, never_default,
1334 NULL);
1335 return NM_SETTING (s_ip4);
1336 } else if (!g_ascii_strcasecmp (value, "shared")) {
1337 g_free (value);
1338 g_object_set (s_ip4,
1339 NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_SHARED,
1340 NM_SETTING_IP4_CONFIG_NEVER_DEFAULT, never_default,
1341 NULL);
1342 return NM_SETTING (s_ip4);
1343 } else {
1344 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
1345 "Unknown BOOTPROTO '%s'", value);
1346 g_free (value);
1347 goto done;
1348 }
1349 g_free (value);
1350
1351 g_object_set (s_ip4,
1352 NM_SETTING_IP4_CONFIG_METHOD, method,
1353 NM_SETTING_IP4_CONFIG_IGNORE_AUTO_DNS, !svTrueValue (ifcfg, "PEERDNS", TRUE),
1354 NM_SETTING_IP4_CONFIG_IGNORE_AUTO_ROUTES, !svTrueValue (ifcfg, "PEERROUTES", TRUE),
1355 NM_SETTING_IP4_CONFIG_NEVER_DEFAULT, never_default,
1356 NM_SETTING_IP4_CONFIG_MAY_FAIL, !svTrueValue (ifcfg, "IPV4_FAILURE_FATAL", FALSE),
1357 NULL);
1358
1359 if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED) == 0)
1360 return NM_SETTING (s_ip4);
1361
1362 /* Handle DHCP settings */
1363 if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) {
1364 value = svGetValue (ifcfg, "DHCP_HOSTNAME", FALSE);
1365 if (value && strlen (value))
1366 g_object_set (s_ip4, NM_SETTING_IP4_CONFIG_DHCP_HOSTNAME, value, NULL);
1367 g_free (value);
1368
1369 value = svGetValue (ifcfg, "DHCP_CLIENT_ID", FALSE);
1370 if (value && strlen (value))
1371 g_object_set (s_ip4, NM_SETTING_IP4_CONFIG_DHCP_CLIENT_ID, value, NULL);
1372 g_free (value);
1373 }
1374
1375 /* Read static IP addresses.
1376 * Read them even for AUTO method - in this case the addresses are
1377 * added to the automatic ones. Note that this is not currently supported by
1378 * the legacy 'network' service (ifup-eth).
1379 */
1380 for (i = -1; i < 256; i++) {
1381 NMIP4Address *addr = NULL;
1382
1383 if (!read_full_ip4_address (ifcfg, network_file, i, &addr, error))
1384 goto done;
1385 if (!addr) {
1386 /* The first mandatory variable is 2-indexed (IPADDR2)
1387 * Variables IPADDR, IPADDR0 and IPADDR1 are optional */
1388 if (i > 1)
1389 break;
1390 continue;
1391 }
1392
1393 if (!nm_setting_ip4_config_add_address (s_ip4, addr))
1394 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: duplicate IP4 address");
1395 nm_ip4_address_unref (addr);
1396 }
1397
1398 /* DNS servers
1399 * Pick up just IPv4 addresses (IPv6 addresses are taken by make_ip6_setting())
1400 */
1401 for (i = 1; i <= 10; i++) {
1402 char *tag;
1403 guint32 dns;
1404 struct in6_addr ip6_dns;
1405
1406 tag = g_strdup_printf ("DNS%u", i);
1407 if (!read_ip4_address (ifcfg, tag, &dns, error)) {
1408 gboolean valid = TRUE;
1409
1410 /* Ignore IPv6 addresses */
1411 dns = 0;
1412 value = svGetValue (ifcfg, tag, FALSE);
1413 if (value)
1414 valid = parse_ip6_address (value, &ip6_dns, NULL);
1415 g_free (value);
1416
1417 if (!valid) {
1418 g_free (tag);
1419 goto done;
1420 }
1421 g_clear_error (error);
1422 }
1423
1424 if (dns && !nm_setting_ip4_config_add_dns (s_ip4, dns))
1425 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: duplicate DNS server %s", tag);
1426 g_free (tag);
1427 }
1428
1429 /* DNS searches */
1430 value = svGetValue (ifcfg, "DOMAIN", FALSE);
1431 if (value) {
1432 char **searches = NULL;
1433
1434 searches = g_strsplit (value, " ", 0);
1435 if (searches) {
1436 char **item;
1437 for (item = searches; *item; item++) {
1438 if (strlen (*item)) {
1439 if (!nm_setting_ip4_config_add_dns_search (s_ip4, *item))
1440 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: duplicate DNS domain '%s'", *item);
1441 }
1442 }
1443 g_strfreev (searches);
1444 }
1445 g_free (value);
1446 }
1447
1448 /* Static routes - route-<name> file */
1449 route_path = utils_get_route_path (ifcfg->fileName);
1450 if (!route_path) {
1451 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
1452 "Could not get route file path for '%s'", ifcfg->fileName);
1453 goto done;
1454 }
1455
1456 /* First test new/legacy syntax */
1457 if (utils_has_route_file_new_syntax (route_path)) {
1458 /* Parse route file in new syntax */
1459 route_ifcfg = utils_get_route_ifcfg (ifcfg->fileName, FALSE);
1460 if (route_ifcfg) {
1461 for (i = 0; i < 256; i++) {
1462 NMIP4Route *route = NULL;
1463
1464 if (!read_one_ip4_route (route_ifcfg, network_file, i, &route, error)) {
1465 svCloseFile (route_ifcfg);
1466 goto done;
1467 }
1468
1469 if (!route)
1470 break;
1471
1472 if (!nm_setting_ip4_config_add_route (s_ip4, route))
1473 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: duplicate IP4 route");
1474 nm_ip4_route_unref (route);
1475 }
1476 svCloseFile (route_ifcfg);
1477 }
1478 } else {
1479 if (!read_route_file_legacy (route_path, s_ip4, error))
1480 goto done;
1481 }
1482
1483 /* Legacy value NM used for a while but is incorrect (rh #459370) */
1484 if (!nm_setting_ip4_config_get_num_dns_searches (s_ip4)) {
1485 value = svGetValue (ifcfg, "SEARCH", FALSE);
1486 if (value) {
1487 char **searches = NULL;
1488
1489 searches = g_strsplit (value, " ", 0);
1490 if (searches) {
1491 char **item;
1492 for (item = searches; *item; item++) {
1493 if (strlen (*item)) {
1494 if (!nm_setting_ip4_config_add_dns_search (s_ip4, *item))
1495 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: duplicate DNS search '%s'", *item);
1496 }
1497 }
1498 g_strfreev (searches);
1499 }
1500 g_free (value);
1501 }
1502 }
1503
1504 return NM_SETTING (s_ip4);
1505
1506 done:
1507 g_free (route_path);
1508 g_object_unref (s_ip4);
1509 return NULL;
1510 }
1511
1512 static NMSetting *
1513 make_ip6_setting (shvarFile *ifcfg,
1514 const char *network_file,
1515 const char *iscsiadm_path,
1516 GError **error)
1517 {
1518 NMSettingIP6Config *s_ip6 = NULL;
1519 char *value = NULL;
1520 char *str_value;
1521 char *route6_path = NULL;
1522 gboolean ipv6init, ipv6forwarding, ipv6_autoconf, dhcp6 = FALSE;
1523 char *method = NM_SETTING_IP6_CONFIG_METHOD_MANUAL;
1524 char *ipv6addr, *ipv6addr_secondaries;
1525 char **list = NULL, **iter;
1526 guint32 i;
1527 shvarFile *network_ifcfg;
1528 gboolean never_default = FALSE;
1529 gboolean ip6_privacy = FALSE, ip6_privacy_prefer_public_ip;
1530 char *ip6_privacy_str;
1531 NMSettingIP6ConfigPrivacy ip6_privacy_val;
1532
1533 s_ip6 = (NMSettingIP6Config *) nm_setting_ip6_config_new ();
1534
1535 /* First check if IPV6_DEFROUTE is set for this device; IPV6_DEFROUTE has the
1536 * opposite meaning from never-default. The default if IPV6_DEFROUTE is not
1537 * specified is IPV6_DEFROUTE=yes which means that this connection can be used
1538 * as a default route
1539 */
1540 never_default = !svTrueValue (ifcfg, "IPV6_DEFROUTE", TRUE);
1541
1542 /* Then check if IPV6_DEFAULTGW or IPV6_DEFAULTDEV is specified;
1543 * they are global and override IPV6_DEFROUTE
1544 * When both are set, the device specified in IPV6_DEFAULTGW takes preference.
1545 */
1546 network_ifcfg = svNewFile (network_file);
1547 if (network_ifcfg) {
1548 char *ipv6_defaultgw, *ipv6_defaultdev;
1549 char *default_dev = NULL;
1550
1551 /* Get the connection ifcfg device name and the global default route device */
1552 value = svGetValue (ifcfg, "DEVICE", FALSE);
1553 ipv6_defaultgw = svGetValue (network_ifcfg, "IPV6_DEFAULTGW", FALSE);
1554 ipv6_defaultdev = svGetValue (network_ifcfg, "IPV6_DEFAULTDEV", FALSE);
1555
1556 if (ipv6_defaultgw) {
1557 default_dev = strchr (ipv6_defaultgw, '%');
1558 if (default_dev)
1559 default_dev++;
1560 }
1561 if (!default_dev)
1562 default_dev = ipv6_defaultdev;
1563
1564 /* If there was a global default route device specified, then only connections
1565 * for that device can be the default connection.
1566 */
1567 if (default_dev && value)
1568 never_default = !!strcmp (value, default_dev);
1569
1570 g_free (ipv6_defaultgw);
1571 g_free (ipv6_defaultdev);
1572 g_free (value);
1573 svCloseFile (network_ifcfg);
1574 }
1575
1576 /* Find out method property */
1577 /* Is IPV6 enabled? Set method to "ignored", when not enabled */
1578 str_value = svGetValue (ifcfg, "IPV6INIT", FALSE);
1579 ipv6init = svTrueValue (ifcfg, "IPV6INIT", FALSE);
1580 if (!str_value) {
1581 network_ifcfg = svNewFile (network_file);
1582 if (network_ifcfg) {
1583 ipv6init = svTrueValue (network_ifcfg, "IPV6INIT", FALSE);
1584 svCloseFile (network_ifcfg);
1585 }
1586 }
1587 g_free (str_value);
1588
1589 if (!ipv6init)
1590 method = NM_SETTING_IP6_CONFIG_METHOD_IGNORE; /* IPv6 is disabled */
1591 else {
1592 ipv6forwarding = svTrueValue (ifcfg, "IPV6FORWARDING", FALSE);
1593 ipv6_autoconf = svTrueValue (ifcfg, "IPV6_AUTOCONF", !ipv6forwarding);
1594 dhcp6 = svTrueValue (ifcfg, "DHCPV6C", FALSE);
1595
1596 if (ipv6_autoconf)
1597 method = NM_SETTING_IP6_CONFIG_METHOD_AUTO;
1598 else if (dhcp6)
1599 method = NM_SETTING_IP6_CONFIG_METHOD_DHCP;
1600 else {
1601 /* IPV6_AUTOCONF=no and no IPv6 address -> method 'link-local' */
1602 str_value = svGetValue (ifcfg, "IPV6ADDR", FALSE);
1603 if (!str_value)
1604 str_value = svGetValue (ifcfg, "IPV6ADDR_SECONDARIES", FALSE);
1605
1606 if (!str_value)
1607 method = NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL;
1608 g_free (str_value);
1609 }
1610 }
1611 /* TODO - handle other methods */
1612
1613 /* Read IPv6 Privacy Extensions configuration */
1614 ip6_privacy_str = svGetValue (ifcfg, "IPV6_PRIVACY", FALSE);
1615 if (ip6_privacy_str) {
1616 ip6_privacy = svTrueValue (ifcfg, "IPV6_PRIVACY", FALSE);
1617 if (!ip6_privacy)
1618 ip6_privacy = g_strcmp0 (ip6_privacy_str, "rfc4941") == 0 ||
1619 g_strcmp0 (ip6_privacy_str, "rfc3041") == 0;
1620 }
1621 ip6_privacy_prefer_public_ip = svTrueValue (ifcfg, "IPV6_PRIVACY_PREFER_PUBLIC_IP", FALSE);
1622 ip6_privacy_val = ip6_privacy_str ?
1623 (ip6_privacy ?
1624 (ip6_privacy_prefer_public_ip ? NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR : NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR) :
1625 NM_SETTING_IP6_CONFIG_PRIVACY_DISABLED) :
1626 NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN;
1627 g_free (ip6_privacy_str);
1628
1629 g_object_set (s_ip6,
1630 NM_SETTING_IP6_CONFIG_METHOD, method,
1631 NM_SETTING_IP6_CONFIG_IGNORE_AUTO_DNS, !svTrueValue (ifcfg, "IPV6_PEERDNS", TRUE),
1632 NM_SETTING_IP6_CONFIG_IGNORE_AUTO_ROUTES, !svTrueValue (ifcfg, "IPV6_PEERROUTES", TRUE),
1633 NM_SETTING_IP6_CONFIG_NEVER_DEFAULT, never_default,
1634 NM_SETTING_IP6_CONFIG_MAY_FAIL, !svTrueValue (ifcfg, "IPV6_FAILURE_FATAL", FALSE),
1635 NM_SETTING_IP6_CONFIG_IP6_PRIVACY, ip6_privacy_val,
1636 NULL);
1637
1638 /* Don't bother to read IP, DNS and routes when IPv6 is disabled */
1639 if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE) == 0)
1640 return NM_SETTING (s_ip6);
1641
1642 if ( !strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO)
1643 || !strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_DHCP)) {
1644 /* METHOD_AUTO may trigger DHCPv6, so save the hostname to send to DHCP */
1645 value = svGetValue (ifcfg, "DHCP_HOSTNAME", FALSE);
1646 if (value && value[0])
1647 g_object_set (s_ip6, NM_SETTING_IP6_CONFIG_DHCP_HOSTNAME, value, NULL);
1648 g_free (value);
1649 }
1650
1651 /* Read static IP addresses.
1652 * Read them even for AUTO and DHCP methods - in this case the addresses are
1653 * added to the automatic ones. Note that this is not currently supported by
1654 * the legacy 'network' service (ifup-eth).
1655 */
1656 ipv6addr = svGetValue (ifcfg, "IPV6ADDR", FALSE);
1657 ipv6addr_secondaries = svGetValue (ifcfg, "IPV6ADDR_SECONDARIES", FALSE);
1658
1659 value = g_strjoin (ipv6addr && ipv6addr_secondaries ? " " : NULL,
1660 ipv6addr ? ipv6addr : "",
1661 ipv6addr_secondaries ? ipv6addr_secondaries : "",
1662 NULL);
1663 g_free (ipv6addr);
1664 g_free (ipv6addr_secondaries);
1665
1666 list = g_strsplit_set (value, " ", 0);
1667 g_free (value);
1668 for (iter = list, i = 0; iter && *iter; iter++, i++) {
1669 NMIP6Address *addr = NULL;
1670
1671 if (!parse_full_ip6_address (ifcfg, network_file, *iter, i, &addr, error)) {
1672 g_strfreev (list);
1673 goto error;
1674 }
1675
1676 if (!nm_setting_ip6_config_add_address (s_ip6, addr))
1677 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: duplicate IP6 address");
1678 nm_ip6_address_unref (addr);
1679 }
1680 g_strfreev (list);
1681
1682 /* DNS servers
1683 * Pick up just IPv6 addresses (IPv4 addresses are taken by make_ip4_setting())
1684 */
1685 for (i = 1; i <= 10; i++) {
1686 char *tag;
1687 struct in6_addr ip6_dns;
1688 guint32 ip4_addr;
1689
1690 tag = g_strdup_printf ("DNS%u", i);
1691 value = svGetValue (ifcfg, tag, FALSE);
1692 if (!value) {
1693 g_free (tag);
1694 break; /* all done */
1695 }
1696
1697 ip6_dns = in6addr_any;
1698 if (parse_ip6_address (value, &ip6_dns, NULL)) {
1699 if (!IN6_IS_ADDR_UNSPECIFIED (&ip6_dns) && !nm_setting_ip6_config_add_dns (s_ip6, &ip6_dns))
1700 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: duplicate DNS server %s", tag);
1701 } else {
1702 /* Maybe an IPv4 address? If so ignore it */
1703 if (inet_pton (AF_INET, value, &ip4_addr) != 1) {
1704 g_free (tag);
1705 g_free (value);
1706 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: duplicate IP6 address");
1707 goto error;
1708 }
1709 }
1710
1711 g_free (tag);
1712 g_free (value);
1713 }
1714
1715 /* DNS searches ('DOMAIN' key) are read by make_ip4_setting() and included in NMSettingIP4Config */
1716
1717 /* Read static routes from route6-<interface> file */
1718 route6_path = utils_get_route6_path (ifcfg->fileName);
1719 if (!route6_path) {
1720 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
1721 "Could not get route6 file path for '%s'", ifcfg->fileName);
1722 goto error;
1723 }
1724
1725 if (!read_route6_file (route6_path, s_ip6, error))
1726 goto error;
1727
1728 g_free (route6_path);
1729 return NM_SETTING (s_ip6);
1730
1731 error:
1732 g_free (route6_path);
1733 g_object_unref (s_ip6);
1734 return NULL;
1735 }
1736
1737 static void
1738 check_if_bond_slave (shvarFile *ifcfg,
1739 NMSettingConnection *s_con)
1740 {
1741 char *value;
1742
1743 value = svGetValue (ifcfg, "MASTER", FALSE);
1744 if (value) {
1745 g_object_set (s_con, NM_SETTING_CONNECTION_MASTER, value, NULL);
1746 g_object_set (s_con,
1747 NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_BOND_SETTING_NAME,
1748 NULL);
1749 g_free (value);
1750 }
1751 }
1752
1753 static void
1754 check_if_team_slave (shvarFile *ifcfg,
1755 NMSettingConnection *s_con)
1756 {
1757 char *value;
1758
1759 value = svGetValue (ifcfg, "DEVICETYPE", FALSE);
1760 if (!value)
1761 return;
1762 if (strcasecmp (value, TYPE_TEAM_PORT)) {
1763 g_free (value);
1764 return;
1765 }
1766 g_free (value);
1767 value = svGetValue (ifcfg, "TEAM_MASTER", FALSE);
1768 if (!value)
1769 return;
1770 g_object_set (s_con, NM_SETTING_CONNECTION_MASTER, value, NULL);
1771 g_object_set (s_con, NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_TEAM_SETTING_NAME, NULL);
1772 g_free (value);
1773 }
1774
1775 static gboolean
1776 add_one_wep_key (shvarFile *ifcfg,
1777 const char *shvar_key,
1778 guint8 key_idx,
1779 gboolean passphrase,
1780 NMSettingWirelessSecurity *s_wsec,
1781 GError **error)
1782 {
1783 char *key = NULL;
1784 char *value = NULL;
1785 gboolean success = FALSE;
1786
1787 g_return_val_if_fail (ifcfg != NULL, FALSE);
1788 g_return_val_if_fail (shvar_key != NULL, FALSE);
1789 g_return_val_if_fail (key_idx <= 3, FALSE);
1790 g_return_val_if_fail (s_wsec != NULL, FALSE);
1791
1792 value = svGetValue (ifcfg, shvar_key, FALSE);
1793 if (!value || !strlen (value)) {
1794 g_free (value);
1795 return TRUE;
1796 }
1797
1798 /* Validate keys */
1799 if (passphrase) {
1800 if (strlen (value) && strlen (value) < 64) {
1801 key = g_strdup (value);
1802 g_object_set (G_OBJECT (s_wsec),
1803 NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE,
1804 NM_WEP_KEY_TYPE_PASSPHRASE,
1805 NULL);
1806 }
1807 } else {
1808 if (strlen (value) == 10 || strlen (value) == 26) {
1809 /* Hexadecimal WEP key */
1810 char *p = value;
1811
1812 while (*p) {
1813 if (!g_ascii_isxdigit (*p)) {
1814 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
1815 "Invalid hexadecimal WEP key.");
1816 goto out;
1817 }
1818 p++;
1819 }
1820 key = g_strdup (value);
1821 } else if ( !strncmp (value, "s:", 2)
1822 && (strlen (value) == 7 || strlen (value) == 15)) {
1823 /* ASCII key */
1824 char *p = value + 2;
1825
1826 while (*p) {
1827 if (!g_ascii_isprint ((int) (*p))) {
1828 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
1829 "Invalid ASCII WEP key.");
1830 goto out;
1831 }
1832 p++;
1833 }
1834
1835 /* Remove 's:' prefix.
1836 * Don't convert to hex string. wpa_supplicant takes 'wep_key0' option over D-Bus as byte array
1837 * and converts it to hex string itself. Even though we convert hex string keys into a bin string
1838 * before passing to wpa_supplicant, this prevents two unnecessary conversions. And mainly,
1839 * ASCII WEP key doesn't change to HEX WEP key in UI, which could confuse users.
1840 */
1841 key = g_strdup (value + 2);
1842 }
1843 }
1844
1845 if (key) {
1846 nm_setting_wireless_security_set_wep_key (s_wsec, key_idx, key);
1847 g_free (key);
1848 success = TRUE;
1849 } else
1850 g_set_error (error, IFCFG_PLUGIN_ERROR, 0, "Invalid WEP key length.");
1851
1852 out:
1853 g_free (value);
1854 return success;
1855 }
1856
1857 static gboolean
1858 read_wep_keys (shvarFile *ifcfg,
1859 guint8 def_idx,
1860 NMSettingWirelessSecurity *s_wsec,
1861 GError **error)
1862 {
1863 /* Try hex/ascii keys first */
1864 if (!add_one_wep_key (ifcfg, "KEY1", 0, FALSE, s_wsec, error))
1865 return FALSE;
1866 if (!add_one_wep_key (ifcfg, "KEY2", 1, FALSE, s_wsec, error))
1867 return FALSE;
1868 if (!add_one_wep_key (ifcfg, "KEY3", 2, FALSE, s_wsec, error))
1869 return FALSE;
1870 if (!add_one_wep_key (ifcfg, "KEY4", 3, FALSE, s_wsec, error))
1871 return FALSE;
1872 if (!add_one_wep_key (ifcfg, "KEY", def_idx, FALSE, s_wsec, error))
1873 return FALSE;
1874
1875 /* And then passphrases */
1876 if (!add_one_wep_key (ifcfg, "KEY_PASSPHRASE1", 0, TRUE, s_wsec, error))
1877 return FALSE;
1878 if (!add_one_wep_key (ifcfg, "KEY_PASSPHRASE2", 1, TRUE, s_wsec, error))
1879 return FALSE;
1880 if (!add_one_wep_key (ifcfg, "KEY_PASSPHRASE3", 2, TRUE, s_wsec, error))
1881 return FALSE;
1882 if (!add_one_wep_key (ifcfg, "KEY_PASSPHRASE4", 3, TRUE, s_wsec, error))
1883 return FALSE;
1884
1885 return TRUE;
1886 }
1887
1888 static NMSettingSecretFlags
1889 read_secret_flags (shvarFile *ifcfg, const char *flags_key)
1890 {
1891 NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE;
1892 char *val;
1893
1894 g_return_val_if_fail (flags_key != NULL, NM_SETTING_SECRET_FLAG_NONE);
1895 g_return_val_if_fail (flags_key[0] != '\0', NM_SETTING_SECRET_FLAG_NONE);
1896 g_return_val_if_fail (g_str_has_suffix (flags_key, "_FLAGS"), NM_SETTING_SECRET_FLAG_NONE);
1897
1898 val = svGetValue (ifcfg, flags_key, FALSE);
1899 if (val) {
1900 if (strstr (val, SECRET_FLAG_AGENT))
1901 flags |= NM_SETTING_SECRET_FLAG_AGENT_OWNED;
1902 if (strstr (val, SECRET_FLAG_NOT_SAVED))
1903 flags |= NM_SETTING_SECRET_FLAG_NOT_SAVED;
1904 if (strstr (val, SECRET_FLAG_NOT_REQUIRED))
1905 flags |= NM_SETTING_SECRET_FLAG_NOT_REQUIRED;
1906
1907 g_free (val);
1908 }
1909 return flags;
1910 }
1911
1912 static NMSetting *
1913 make_wep_setting (shvarFile *ifcfg,
1914 const char *file,
1915 GError **error)
1916 {
1917 NMSettingWirelessSecurity *s_wsec;
1918 char *value;
1919 shvarFile *keys_ifcfg = NULL;
1920 int default_key_idx = 0;
1921 gboolean has_default_key = FALSE, success;
1922 NMSettingSecretFlags key_flags;
1923
1924 s_wsec = NM_SETTING_WIRELESS_SECURITY (nm_setting_wireless_security_new ());
1925 g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "none", NULL);
1926
1927 value = svGetValue (ifcfg, "DEFAULTKEY", FALSE);
1928 if (value) {
1929 success = get_int (value, &default_key_idx);
1930 if (success && (default_key_idx >= 1) && (default_key_idx <= 4)) {
1931 has_default_key = TRUE;
1932 default_key_idx--; /* convert to [0...3] */
1933 g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_WEP_TX_KEYIDX, default_key_idx, NULL);
1934 } else {
1935 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
1936 "Invalid default WEP key '%s'", value);
1937 g_free (value);
1938 goto error;
1939 }
1940 g_free (value);
1941 }
1942
1943 /* Read WEP key flags */
1944 key_flags = read_secret_flags (ifcfg, "WEP_KEY_FLAGS");
1945 g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_WEP_KEY_FLAGS, key_flags, NULL);
1946
1947 /* Read keys in the ifcfg file if they are system-owned */
1948 if (key_flags == NM_SETTING_SECRET_FLAG_NONE) {
1949 if (!read_wep_keys (ifcfg, default_key_idx, s_wsec, error))
1950 goto error;
1951
1952 /* Try to get keys from the "shadow" key file */
1953 keys_ifcfg = utils_get_keys_ifcfg (file, FALSE);
1954 if (keys_ifcfg) {
1955 if (!read_wep_keys (keys_ifcfg, default_key_idx, s_wsec, error)) {
1956 svCloseFile (keys_ifcfg);
1957 goto error;
1958 }
1959 svCloseFile (keys_ifcfg);
1960 g_assert (error == NULL || *error == NULL);
1961 }
1962 }
1963
1964 value = svGetValue (ifcfg, "SECURITYMODE", FALSE);
1965 if (value) {
1966 char *lcase;
1967
1968 lcase = g_ascii_strdown (value, -1);
1969 g_free (value);
1970
1971 if (!strcmp (lcase, "open")) {
1972 g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open", NULL);
1973 } else if (!strcmp (lcase, "restricted")) {
1974 g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "shared", NULL);
1975 } else {
1976 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
1977 "Invalid WEP authentication algorithm '%s'",
1978 lcase);
1979 g_free (lcase);
1980 goto error;
1981 }
1982 g_free (lcase);
1983 }
1984
1985 /* If no WEP keys were given, and the keys are not agent-owned, and no
1986 * default WEP key index was given, then the connection is unencrypted.
1987 */
1988 if ( !nm_setting_wireless_security_get_wep_key (s_wsec, 0)
1989 && !nm_setting_wireless_security_get_wep_key (s_wsec, 1)
1990 && !nm_setting_wireless_security_get_wep_key (s_wsec, 2)
1991 && !nm_setting_wireless_security_get_wep_key (s_wsec, 3)
1992 && (has_default_key == FALSE)
1993 && (key_flags == NM_SETTING_SECRET_FLAG_NONE)) {
1994 const char *auth_alg;
1995
1996 auth_alg = nm_setting_wireless_security_get_auth_alg (s_wsec);
1997 if (auth_alg && !strcmp (auth_alg, "shared")) {
1998 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
1999 "WEP Shared Key authentication is invalid for "
2000 "unencrypted connections.");
2001 goto error;
2002 }
2003
2004 /* Unencrypted */
2005 g_object_unref (s_wsec);
2006 s_wsec = NULL;
2007 }
2008
2009 return (NMSetting *) s_wsec;
2010
2011 error:
2012 if (s_wsec)
2013 g_object_unref (s_wsec);
2014 return NULL;
2015 }
2016
2017 static gboolean
2018 fill_wpa_ciphers (shvarFile *ifcfg,
2019 NMSettingWirelessSecurity *wsec,
2020 gboolean group,
2021 gboolean adhoc)
2022 {
2023 char *value = NULL, *p;
2024 char **list = NULL, **iter;
2025 int i = 0;
2026
2027 p = value = svGetValue (ifcfg, group ? "CIPHER_GROUP" : "CIPHER_PAIRWISE", TRUE);
2028 if (!value)
2029 return TRUE;
2030
2031 /* Strip quotes */
2032 if (p[0] == '"')
2033 p++;
2034 if (p[strlen (p) - 1] == '"')
2035 p[strlen (p) - 1] = '\0';
2036
2037 list = g_strsplit_set (p, " ", 0);
2038 for (iter = list; iter && *iter; iter++, i++) {
2039 /* Ad-Hoc configurations cannot have pairwise ciphers, and can only
2040 * have one group cipher. Ignore any additional group ciphers and
2041 * any pairwise ciphers specified.
2042 */
2043 if (adhoc) {
2044 if (group && (i > 0)) {
2045 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: ignoring group cipher '%s' (only one group cipher allowed in Ad-Hoc mode)",
2046 *iter);
2047 continue;
2048 } else if (!group) {
2049 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: ignoring pairwise cipher '%s' (pairwise not used in Ad-Hoc mode)",
2050 *iter);
2051 continue;
2052 }
2053 }
2054
2055 if (!strcmp (*iter, "CCMP")) {
2056 if (group)
2057 nm_setting_wireless_security_add_group (wsec, "ccmp");
2058 else
2059 nm_setting_wireless_security_add_pairwise (wsec, "ccmp");
2060 } else if (!strcmp (*iter, "TKIP")) {
2061 if (group)
2062 nm_setting_wireless_security_add_group (wsec, "tkip");
2063 else
2064 nm_setting_wireless_security_add_pairwise (wsec, "tkip");
2065 } else if (group && !strcmp (*iter, "WEP104"))
2066 nm_setting_wireless_security_add_group (wsec, "wep104");
2067 else if (group && !strcmp (*iter, "WEP40"))
2068 nm_setting_wireless_security_add_group (wsec, "wep40");
2069 else {
2070 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: ignoring invalid %s cipher '%s'",
2071 group ? "CIPHER_GROUP" : "CIPHER_PAIRWISE",
2072 *iter);
2073 }
2074 }
2075
2076 if (list)
2077 g_strfreev (list);
2078 g_free (value);
2079 return TRUE;
2080 }
2081
2082 #define WPA_PMK_LEN 32
2083
2084 static char *
2085 parse_wpa_psk (shvarFile *ifcfg,
2086 const char *file,
2087 const GByteArray *ssid,
2088 GError **error)
2089 {
2090 shvarFile *keys_ifcfg;
2091 char *psk = NULL, *p, *hashed = NULL;
2092 size_t plen;
2093 gboolean quoted = FALSE;
2094
2095 /* Passphrase must be between 10 and 66 characters in length because WPA
2096 * hex keys are exactly 64 characters (no quoting), and WPA passphrases
2097 * are between 8 and 63 characters (inclusive), plus optional quoting if
2098 * the passphrase contains spaces.
2099 */
2100
2101 /* Try to get keys from the "shadow" key file */
2102 keys_ifcfg = utils_get_keys_ifcfg (file, FALSE);
2103 if (keys_ifcfg) {
2104 psk = svGetValue (keys_ifcfg, "WPA_PSK", TRUE);
2105 svCloseFile (keys_ifcfg);
2106 }
2107
2108 /* Fall back to the original ifcfg */
2109 if (!psk)
2110 psk = svGetValue (ifcfg, "WPA_PSK", TRUE);
2111
2112 if (!psk)
2113 return NULL;
2114
2115 p = psk;
2116 plen = strlen (p);
2117
2118 if ( (plen >= 2 && (p[0] == '"' || p[0] == '\'') && p[0] == p[plen - 1])
2119 || (plen >= 3 && p[0] == '$' && p[1] == '\'' && p[1] == p[plen - 1]))
2120 quoted = TRUE;
2121
2122 if (!quoted && (strlen (psk) == 64)) {
2123 /* Verify the hex PSK; 64 digits */
2124 while (*p) {
2125 if (!g_ascii_isxdigit (*p++)) {
2126 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2127 "Invalid WPA_PSK (contains non-hexadecimal characters)");
2128 goto out;
2129 }
2130 }
2131 hashed = g_strdup (psk);
2132 } else {
2133 /* Prior to 4f6eef9e77265484555663cf666cde4fa8323469 and
2134 * 28e2e446868b94b92edc4a82aa0bf1e3eda8ec54 the writer may not have
2135 * properly quoted passphrases, so just handle anything that's unquoted
2136 * and between 8 and 63 characters as a passphrase.
2137 */
2138
2139 /* Get rid of the quotes */
2140 hashed = utils_single_unquote_string (p);
2141
2142 /* Length check */
2143 if (strlen (hashed) < 8 || strlen (hashed) > 63) {
2144 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2145 "Invalid WPA_PSK (passphrases must be between "
2146 "8 and 63 characters long (inclusive))");
2147 g_free (hashed);
2148 hashed = NULL;
2149 goto out;
2150 }
2151 }
2152
2153 if (!hashed) {
2154 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2155 "Invalid WPA_PSK (doesn't look like a passphrase or hex key)");
2156 goto out;
2157 }
2158
2159 out:
2160 g_free (psk);
2161 return hashed;
2162 }
2163
2164 static gboolean
2165 eap_simple_reader (const char *eap_method,
2166 shvarFile *ifcfg,
2167 shvarFile *keys,
2168 NMSetting8021x *s_8021x,
2169 gboolean phase2,
2170 GError **error)
2171 {
2172 NMSettingSecretFlags flags;
2173 char *value;
2174
2175 value = svGetValue (ifcfg, "IEEE_8021X_IDENTITY", FALSE);
2176 if (!value) {
2177 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2178 "Missing IEEE_8021X_IDENTITY for EAP method '%s'.",
2179 eap_method);
2180 return FALSE;
2181 }
2182 g_object_set (s_8021x, NM_SETTING_802_1X_IDENTITY, value, NULL);
2183 g_free (value);
2184
2185 flags = read_secret_flags (ifcfg, "IEEE_8021X_PASSWORD_FLAGS");
2186 g_object_set (s_8021x, NM_SETTING_802_1X_PASSWORD_FLAGS, flags, NULL);
2187
2188 /* Only read the password if it's system-owned */
2189 if (flags == NM_SETTING_SECRET_FLAG_NONE) {
2190 value = svGetValue (ifcfg, "IEEE_8021X_PASSWORD", FALSE);
2191 if (!value && keys) {
2192 /* Try the lookaside keys file */
2193 value = svGetValue (keys, "IEEE_8021X_PASSWORD", FALSE);
2194 }
2195
2196 if (!value) {
2197 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2198 "Missing IEEE_8021X_PASSWORD for EAP method '%s'.",
2199 eap_method);
2200 return FALSE;
2201 }
2202
2203 g_object_set (s_8021x, NM_SETTING_802_1X_PASSWORD, value, NULL);
2204 g_free (value);
2205 }
2206
2207 return TRUE;
2208 }
2209
2210 static char *
2211 get_full_file_path (const char *ifcfg_path, const char *file_path)
2212 {
2213 const char *base = file_path;
2214 char *p, *ret, *dirname;
2215
2216 g_return_val_if_fail (ifcfg_path != NULL, NULL);
2217 g_return_val_if_fail (file_path != NULL, NULL);
2218
2219 if (file_path[0] == '/')
2220 return g_strdup (file_path);
2221
2222 p = strrchr (file_path, '/');
2223 if (p)
2224 base = p + 1;
2225
2226 dirname = g_path_get_dirname (ifcfg_path);
2227 ret = g_build_path ("/", dirname, base, NULL);
2228 g_free (dirname);
2229 return ret;
2230 }
2231
2232 static gboolean
2233 eap_tls_reader (const char *eap_method,
2234 shvarFile *ifcfg,
2235 shvarFile *keys,
2236 NMSetting8021x *s_8021x,
2237 gboolean phase2,
2238 GError **error)
2239 {
2240 char *value;
2241 char *ca_cert = NULL;
2242 char *real_path = NULL;
2243 char *client_cert = NULL;
2244 char *privkey = NULL;
2245 char *privkey_password = NULL;
2246 gboolean success = FALSE;
2247 NMSetting8021xCKFormat privkey_format = NM_SETTING_802_1X_CK_FORMAT_UNKNOWN;
2248 const char *ca_cert_key = phase2 ? "IEEE_8021X_INNER_CA_CERT" : "IEEE_8021X_CA_CERT";
2249 const char *pk_pw_key = phase2 ? "IEEE_8021X_INNER_PRIVATE_KEY_PASSWORD": "IEEE_8021X_PRIVATE_KEY_PASSWORD";
2250 const char *pk_key = phase2 ? "IEEE_8021X_INNER_PRIVATE_KEY" : "IEEE_8021X_PRIVATE_KEY";
2251 const char *cli_cert_key = phase2 ? "IEEE_8021X_INNER_CLIENT_CERT" : "IEEE_8021X_CLIENT_CERT";
2252 const char *pk_pw_flags_key = phase2 ? "IEEE_8021X_INNER_PRIVATE_KEY_PASSWORD_FLAGS": "IEEE_8021X_PRIVATE_KEY_PASSWORD_FLAGS";
2253 const char *pk_pw_flags_prop = phase2 ? NM_SETTING_802_1X_PHASE2_PRIVATE_KEY_PASSWORD_FLAGS : NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD_FLAGS;
2254 NMSettingSecretFlags flags;
2255
2256 value = svGetValue (ifcfg, "IEEE_8021X_IDENTITY", FALSE);
2257 if (!value) {
2258 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2259 "Missing IEEE_8021X_IDENTITY for EAP method '%s'.",
2260 eap_method);
2261 return FALSE;
2262 }
2263 g_object_set (s_8021x, NM_SETTING_802_1X_IDENTITY, value, NULL);
2264 g_free (value);
2265
2266 ca_cert = svGetValue (ifcfg, ca_cert_key, FALSE);
2267 if (ca_cert) {
2268 real_path = get_full_file_path (ifcfg->fileName, ca_cert);
2269 if (phase2) {
2270 if (!nm_setting_802_1x_set_phase2_ca_cert (s_8021x,
2271 real_path,
2272 NM_SETTING_802_1X_CK_SCHEME_PATH,
2273 NULL,
2274 error))
2275 goto done;
2276 } else {
2277 if (!nm_setting_802_1x_set_ca_cert (s_8021x,
2278 real_path,
2279 NM_SETTING_802_1X_CK_SCHEME_PATH,
2280 NULL,
2281 error))
2282 goto done;
2283 }
2284 g_free (real_path);
2285 real_path = NULL;
2286 } else {
2287 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: missing %s for EAP"
2288 " method '%s'; this is insecure!",
2289 ca_cert_key,
2290 eap_method);
2291 }
2292
2293 /* Read and set private key password flags */
2294 flags = read_secret_flags (ifcfg, pk_pw_flags_key);
2295 g_object_set (s_8021x, pk_pw_flags_prop, flags, NULL);
2296
2297 /* Read the private key password if it's system-owned */
2298 if (flags == NM_SETTING_SECRET_FLAG_NONE) {
2299 /* Private key password */
2300 privkey_password = svGetValue (ifcfg, pk_pw_key, FALSE);
2301 if (!privkey_password && keys) {
2302 /* Try the lookaside keys file */
2303 privkey_password = svGetValue (keys, pk_pw_key, FALSE);
2304 }
2305
2306 if (!privkey_password) {
2307 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2308 "Missing %s for EAP method '%s'.",
2309 pk_pw_key,
2310 eap_method);
2311 goto done;
2312 }
2313 }
2314
2315 /* The private key itself */
2316 privkey = svGetValue (ifcfg, pk_key, FALSE);
2317 if (!privkey) {
2318 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2319 "Missing %s for EAP method '%s'.",
2320 pk_key,
2321 eap_method);
2322 goto done;
2323 }
2324
2325 real_path = get_full_file_path (ifcfg->fileName, privkey);
2326 if (phase2) {
2327 if (!nm_setting_802_1x_set_phase2_private_key (s_8021x,
2328 real_path,
2329 privkey_password,
2330 NM_SETTING_802_1X_CK_SCHEME_PATH,
2331 &privkey_format,
2332 error))
2333 goto done;
2334 } else {
2335 if (!nm_setting_802_1x_set_private_key (s_8021x,
2336 real_path,
2337 privkey_password,
2338 NM_SETTING_802_1X_CK_SCHEME_PATH,
2339 &privkey_format,
2340 error))
2341 goto done;
2342 }
2343 g_free (real_path);
2344 real_path = NULL;
2345
2346 /* Only set the client certificate if the private key is not PKCS#12 format,
2347 * as NM (due to supplicant restrictions) requires. If the key was PKCS#12,
2348 * then nm_setting_802_1x_set_private_key() already set the client certificate
2349 * to the same value as the private key.
2350 */
2351 if ( privkey_format == NM_SETTING_802_1X_CK_FORMAT_RAW_KEY
2352 || privkey_format == NM_SETTING_802_1X_CK_FORMAT_X509) {
2353 client_cert = svGetValue (ifcfg, cli_cert_key, FALSE);
2354 if (!client_cert) {
2355 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2356 "Missing %s for EAP method '%s'.",
2357 cli_cert_key,
2358 eap_method);
2359 goto done;
2360 }
2361
2362 real_path = get_full_file_path (ifcfg->fileName, client_cert);
2363 if (phase2) {
2364 if (!nm_setting_802_1x_set_phase2_client_cert (s_8021x,
2365 real_path,
2366 NM_SETTING_802_1X_CK_SCHEME_PATH,
2367 NULL,
2368 error))
2369 goto done;
2370 } else {
2371 if (!nm_setting_802_1x_set_client_cert (s_8021x,
2372 real_path,
2373 NM_SETTING_802_1X_CK_SCHEME_PATH,
2374 NULL,
2375 error))
2376 goto done;
2377 }
2378 g_free (real_path);
2379 real_path = NULL;
2380 }
2381
2382 success = TRUE;
2383
2384 done:
2385 g_free (real_path);
2386 g_free (ca_cert);
2387 g_free (client_cert);
2388 g_free (privkey);
2389 g_free (privkey_password);
2390 return success;
2391 }
2392
2393 static gboolean
2394 eap_peap_reader (const char *eap_method,
2395 shvarFile *ifcfg,
2396 shvarFile *keys,
2397 NMSetting8021x *s_8021x,
2398 gboolean phase2,
2399 GError **error)
2400 {
2401 char *anon_ident = NULL;
2402 char *ca_cert = NULL;
2403 char *real_cert_path = NULL;
2404 char *inner_auth = NULL;
2405 char *peapver = NULL;
2406 char *lower;
2407 char **list = NULL, **iter;
2408 gboolean success = FALSE;
2409
2410 ca_cert = svGetValue (ifcfg, "IEEE_8021X_CA_CERT", FALSE);
2411 if (ca_cert) {
2412 real_cert_path = get_full_file_path (ifcfg->fileName, ca_cert);
2413 if (!nm_setting_802_1x_set_ca_cert (s_8021x,
2414 real_cert_path,
2415 NM_SETTING_802_1X_CK_SCHEME_PATH,
2416 NULL,
2417 error))
2418 goto done;
2419 } else {
2420 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: missing "
2421 "IEEE_8021X_CA_CERT for EAP method '%s'; this is"
2422 " insecure!",
2423 eap_method);
2424 }
2425
2426 peapver = svGetValue (ifcfg, "IEEE_8021X_PEAP_VERSION", FALSE);
2427 if (peapver) {
2428 if (!strcmp (peapver, "0"))
2429 g_object_set (s_8021x, NM_SETTING_802_1X_PHASE1_PEAPVER, "0", NULL);
2430 else if (!strcmp (peapver, "1"))
2431 g_object_set (s_8021x, NM_SETTING_802_1X_PHASE1_PEAPVER, "1", NULL);
2432 else {
2433 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2434 "Unknown IEEE_8021X_PEAP_VERSION value '%s'",
2435 peapver);
2436 goto done;
2437 }
2438 }
2439
2440 if (svTrueValue (ifcfg, "IEEE_8021X_PEAP_FORCE_NEW_LABEL", FALSE))
2441 g_object_set (s_8021x, NM_SETTING_802_1X_PHASE1_PEAPLABEL, "1", NULL);
2442
2443 anon_ident = svGetValue (ifcfg, "IEEE_8021X_ANON_IDENTITY", FALSE);
2444 if (anon_ident && strlen (anon_ident))
2445 g_object_set (s_8021x, NM_SETTING_802_1X_ANONYMOUS_IDENTITY, anon_ident, NULL);
2446
2447 inner_auth = svGetValue (ifcfg, "IEEE_8021X_INNER_AUTH_METHODS", FALSE);
2448 if (!inner_auth) {
2449 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2450 "Missing IEEE_8021X_INNER_AUTH_METHODS.");
2451 goto done;
2452 }
2453
2454 /* Handle options for the inner auth method */
2455 list = g_strsplit (inner_auth, " ", 0);
2456 for (iter = list; iter && *iter; iter++) {
2457 if (!strlen (*iter))
2458 continue;
2459
2460 if ( !strcmp (*iter, "MSCHAPV2")
2461 || !strcmp (*iter, "MD5")
2462 || !strcmp (*iter, "GTC")) {
2463 if (!eap_simple_reader (*iter, ifcfg, keys, s_8021x, TRUE, error))
2464 goto done;
2465 } else if (!strcmp (*iter, "TLS")) {
2466 if (!eap_tls_reader (*iter, ifcfg, keys, s_8021x, TRUE, error))
2467 goto done;
2468 } else {
2469 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2470 "Unknown IEEE_8021X_INNER_AUTH_METHOD '%s'.",
2471 *iter);
2472 goto done;
2473 }
2474
2475 lower = g_ascii_strdown (*iter, -1);
2476 g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTH, lower, NULL);
2477 g_free (lower);
2478 break;
2479 }
2480
2481 if (!nm_setting_802_1x_get_phase2_auth (s_8021x)) {
2482 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2483 "No valid IEEE_8021X_INNER_AUTH_METHODS found.");
2484 goto done;
2485 }
2486
2487 success = TRUE;
2488
2489 done:
2490 if (list)
2491 g_strfreev (list);
2492 g_free (inner_auth);
2493 g_free (peapver);
2494 g_free (real_cert_path);
2495 g_free (ca_cert);
2496 g_free (anon_ident);
2497 return success;
2498 }
2499
2500 static gboolean
2501 eap_ttls_reader (const char *eap_method,
2502 shvarFile *ifcfg,
2503 shvarFile *keys,
2504 NMSetting8021x *s_8021x,
2505 gboolean phase2,
2506 GError **error)
2507 {
2508 gboolean success = FALSE;
2509 char *anon_ident = NULL;
2510 char *ca_cert = NULL;
2511 char *real_cert_path = NULL;
2512 char *inner_auth = NULL;
2513 char *tmp;
2514 char **list = NULL, **iter;
2515
2516 ca_cert = svGetValue (ifcfg, "IEEE_8021X_CA_CERT", FALSE);
2517 if (ca_cert) {
2518 real_cert_path = get_full_file_path (ifcfg->fileName, ca_cert);
2519 if (!nm_setting_802_1x_set_ca_cert (s_8021x,
2520 real_cert_path,
2521 NM_SETTING_802_1X_CK_SCHEME_PATH,
2522 NULL,
2523 error))
2524 goto done;
2525 } else {
2526 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: missing "
2527 "IEEE_8021X_CA_CERT for EAP method '%s'; this is"
2528 " insecure!",
2529 eap_method);
2530 }
2531
2532 anon_ident = svGetValue (ifcfg, "IEEE_8021X_ANON_IDENTITY", FALSE);
2533 if (anon_ident && strlen (anon_ident))
2534 g_object_set (s_8021x, NM_SETTING_802_1X_ANONYMOUS_IDENTITY, anon_ident, NULL);
2535
2536 tmp = svGetValue (ifcfg, "IEEE_8021X_INNER_AUTH_METHODS", FALSE);
2537 if (!tmp) {
2538 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2539 "Missing IEEE_8021X_INNER_AUTH_METHODS.");
2540 goto done;
2541 }
2542
2543 inner_auth = g_ascii_strdown (tmp, -1);
2544 g_free (tmp);
2545
2546 /* Handle options for the inner auth method */
2547 list = g_strsplit (inner_auth, " ", 0);
2548 for (iter = list; iter && *iter; iter++) {
2549 if (!strlen (*iter))
2550 continue;
2551
2552 if ( !strcmp (*iter, "mschapv2")
2553 || !strcmp (*iter, "mschap")
2554 || !strcmp (*iter, "pap")
2555 || !strcmp (*iter, "chap")) {
2556 if (!eap_simple_reader (*iter, ifcfg, keys, s_8021x, TRUE, error))
2557 goto done;
2558 g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTH, *iter, NULL);
2559 } else if (!strcmp (*iter, "eap-tls")) {
2560 if (!eap_tls_reader (*iter, ifcfg, keys, s_8021x, TRUE, error))
2561 goto done;
2562 g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTHEAP, "tls", NULL);
2563 } else if (!strcmp (*iter, "eap-mschapv2") || !strcmp (*iter, "eap-md5")) {
2564 if (!eap_simple_reader (*iter, ifcfg, keys, s_8021x, TRUE, error))
2565 goto done;
2566 g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTHEAP, (*iter + strlen ("eap-")), NULL);
2567 } else {
2568 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2569 "Unknown IEEE_8021X_INNER_AUTH_METHOD '%s'.",
2570 *iter);
2571 goto done;
2572 }
2573 break;
2574 }
2575
2576 success = TRUE;
2577
2578 done:
2579 if (list)
2580 g_strfreev (list);
2581 g_free (inner_auth);
2582 g_free (real_cert_path);
2583 g_free (ca_cert);
2584 g_free (anon_ident);
2585 return success;
2586 }
2587
2588 static gboolean
2589 eap_fast_reader (const char *eap_method,
2590 shvarFile *ifcfg,
2591 shvarFile *keys,
2592 NMSetting8021x *s_8021x,
2593 gboolean phase2,
2594 GError **error)
2595 {
2596 char *anon_ident = NULL;
2597 char *pac_file = NULL;
2598 char *real_pac_path = NULL;
2599 char *inner_auth = NULL;
2600 char *fast_provisioning = NULL;
2601 char *lower;
2602 char **list = NULL, **iter;
2603 const char* pac_prov_str;
2604 gboolean allow_unauth = FALSE, allow_auth = FALSE;
2605 gboolean success = FALSE;
2606
2607 pac_file = svGetValue (ifcfg, "IEEE_8021X_PAC_FILE", FALSE);
2608 if (pac_file) {
2609 real_pac_path = get_full_file_path (ifcfg->fileName, pac_file);
2610 g_object_set (s_8021x, NM_SETTING_802_1X_PAC_FILE, real_pac_path, NULL);
2611 }
2612
2613 fast_provisioning = svGetValue (ifcfg, "IEEE_8021X_FAST_PROVISIONING", FALSE);
2614 if (fast_provisioning) {
2615 list = g_strsplit_set (fast_provisioning, " \t", 0);
2616 for (iter = list; iter && *iter; iter++) {
2617 if (**iter == '\0')
2618 continue;
2619 if (strcmp (*iter, "allow-unauth") == 0)
2620 allow_unauth = TRUE;
2621 else if (strcmp (*iter, "allow-auth") == 0)
2622 allow_auth = TRUE;
2623 else {
2624 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: invalid IEEE_8021X_FAST_PROVISIONING '%s' "
2625 "(space-separated list of these values [allow-auth, allow-unauth] expected)",
2626 *iter);
2627 }
2628 }
2629 g_strfreev (list);
2630 list = NULL;
2631 }
2632 pac_prov_str = allow_unauth ? (allow_auth ? "3" : "1") : (allow_auth ? "2" : "0");
2633 g_object_set (s_8021x, NM_SETTING_802_1X_PHASE1_FAST_PROVISIONING, pac_prov_str, NULL);
2634
2635 if (!pac_file && !(allow_unauth || allow_auth)) {
2636 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2637 "IEEE_8021X_PAC_FILE not provided and EAP-FAST automatic PAC provisioning disabled.");
2638 goto done;
2639 }
2640
2641 anon_ident = svGetValue (ifcfg, "IEEE_8021X_ANON_IDENTITY", FALSE);
2642 if (anon_ident && strlen (anon_ident))
2643 g_object_set (s_8021x, NM_SETTING_802_1X_ANONYMOUS_IDENTITY, anon_ident, NULL);
2644
2645 inner_auth = svGetValue (ifcfg, "IEEE_8021X_INNER_AUTH_METHODS", FALSE);
2646 if (!inner_auth) {
2647 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2648 "Missing IEEE_8021X_INNER_AUTH_METHODS.");
2649 goto done;
2650 }
2651
2652 /* Handle options for the inner auth method */
2653 list = g_strsplit (inner_auth, " ", 0);
2654 for (iter = list; iter && *iter; iter++) {
2655 if (!strlen (*iter))
2656 continue;
2657
2658 if ( !strcmp (*iter, "MSCHAPV2")
2659 || !strcmp (*iter, "GTC")) {
2660 if (!eap_simple_reader (*iter, ifcfg, keys, s_8021x, TRUE, error))
2661 goto done;
2662 } else {
2663 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2664 "Unknown IEEE_8021X_INNER_AUTH_METHOD '%s'.",
2665 *iter);
2666 goto done;
2667 }
2668
2669 lower = g_ascii_strdown (*iter, -1);
2670 g_object_set (s_8021x, NM_SETTING_802_1X_PHASE2_AUTH, lower, NULL);
2671 g_free (lower);
2672 break;
2673 }
2674
2675 if (!nm_setting_802_1x_get_phase2_auth (s_8021x)) {
2676 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2677 "No valid IEEE_8021X_INNER_AUTH_METHODS found.");
2678 goto done;
2679 }
2680
2681 success = TRUE;
2682
2683 done:
2684 g_strfreev (list);
2685 g_free (inner_auth);
2686 g_free (fast_provisioning);
2687 g_free (real_pac_path);
2688 g_free (pac_file);
2689 g_free (anon_ident);
2690 return success;
2691 }
2692
2693 typedef struct {
2694 const char *method;
2695 gboolean (*reader)(const char *eap_method,
2696 shvarFile *ifcfg,
2697 shvarFile *keys,
2698 NMSetting8021x *s_8021x,
2699 gboolean phase2,
2700 GError **error);
2701 gboolean wifi_phase2_only;
2702 } EAPReader;
2703
2704 static EAPReader eap_readers[] = {
2705 { "md5", eap_simple_reader, TRUE },
2706 { "pap", eap_simple_reader, TRUE },
2707 { "chap", eap_simple_reader, TRUE },
2708 { "mschap", eap_simple_reader, TRUE },
2709 { "mschapv2", eap_simple_reader, TRUE },
2710 { "leap", eap_simple_reader, FALSE },
2711 { "pwd", eap_simple_reader, FALSE },
2712 { "tls", eap_tls_reader, FALSE },
2713 { "peap", eap_peap_reader, FALSE },
2714 { "ttls", eap_ttls_reader, FALSE },
2715 { "fast", eap_fast_reader, FALSE },
2716 { NULL, NULL }
2717 };
2718
2719 static NMSetting8021x *
2720 fill_8021x (shvarFile *ifcfg,
2721 const char *file,
2722 const char *key_mgmt,
2723 gboolean wifi,
2724 GError **error)
2725 {
2726 NMSetting8021x *s_8021x;
2727 shvarFile *keys = NULL;
2728 char *value;
2729 char **list = NULL, **iter;
2730
2731 value = svGetValue (ifcfg, "IEEE_8021X_EAP_METHODS", FALSE);
2732 if (!value) {
2733 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2734 "Missing IEEE_8021X_EAP_METHODS for key management '%s'",
2735 key_mgmt);
2736 return NULL;
2737 }
2738
2739 list = g_strsplit (value, " ", 0);
2740 g_free (value);
2741
2742 s_8021x = (NMSetting8021x *) nm_setting_802_1x_new ();
2743
2744 /* Read in the lookaside keys file, if present */
2745 keys = utils_get_keys_ifcfg (file, FALSE);
2746
2747 /* Validate and handle each EAP method */
2748 for (iter = list; iter && *iter; iter++) {
2749 EAPReader *eap = &eap_readers[0];
2750 gboolean found = FALSE;
2751 char *lower = NULL;
2752
2753 lower = g_ascii_strdown (*iter, -1);
2754 while (eap->method && !found) {
2755 if (strcmp (eap->method, lower))
2756 goto next;
2757
2758 /* Some EAP methods don't provide keying material, thus they
2759 * cannot be used with WiFi unless they are an inner method
2760 * used with TTLS or PEAP or whatever.
2761 */
2762 if (wifi && eap->wifi_phase2_only) {
2763 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: ignored invalid "
2764 "IEEE_8021X_EAP_METHOD '%s'; not allowed for wifi.",
2765 lower);
2766 goto next;
2767 }
2768
2769 /* Parse EAP method specific options */
2770 if (!(*eap->reader)(lower, ifcfg, keys, s_8021x, FALSE, error)) {
2771 g_free (lower);
2772 goto error;
2773 }
2774 nm_setting_802_1x_add_eap_method (s_8021x, lower);
2775 found = TRUE;
2776
2777 next:
2778 eap++;
2779 }
2780
2781 if (!found) {
2782 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: ignored unknown"
2783 "IEEE_8021X_EAP_METHOD '%s'.",
2784 lower);
2785 }
2786 g_free (lower);
2787 }
2788
2789 if (nm_setting_802_1x_get_num_eap_methods (s_8021x) == 0) {
2790 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2791 "No valid EAP methods found in IEEE_8021X_EAP_METHODS.");
2792 goto error;
2793 }
2794
2795 if (list)
2796 g_strfreev (list);
2797 if (keys)
2798 svCloseFile (keys);
2799 return s_8021x;
2800
2801 error:
2802 if (list)
2803 g_strfreev (list);
2804 if (keys)
2805 svCloseFile (keys);
2806 g_object_unref (s_8021x);
2807 return NULL;
2808 }
2809
2810 static NMSetting *
2811 make_wpa_setting (shvarFile *ifcfg,
2812 const char *file,
2813 const GByteArray *ssid,
2814 gboolean adhoc,
2815 NMSetting8021x **s_8021x,
2816 GError **error)
2817 {
2818 NMSettingWirelessSecurity *wsec;
2819 char *value, *psk, *lower;
2820 gboolean wpa_psk = FALSE, wpa_eap = FALSE, ieee8021x = FALSE;
2821
2822 wsec = NM_SETTING_WIRELESS_SECURITY (nm_setting_wireless_security_new ());
2823
2824 value = svGetValue (ifcfg, "KEY_MGMT", FALSE);
(13) Event cond_true: |
Condition "!g_strcmp0(value, "WPA-PSK")", taking true branch |
2825 wpa_psk = !g_strcmp0 (value, "WPA-PSK");
(14) Event cond_true: |
Condition "!g_strcmp0(value, "WPA-EAP")", taking true branch |
2826 wpa_eap = !g_strcmp0 (value, "WPA-EAP");
(15) Event cond_true: |
Condition "!g_strcmp0(value, "IEEE8021X")", taking true branch |
2827 ieee8021x = !g_strcmp0 (value, "IEEE8021X");
(16) Event cond_false: |
Condition "!wpa_psk", taking false branch |
2828 if (!wpa_psk && !wpa_eap && !ieee8021x)
(17) Event if_end: |
End of if statement |
2829 goto error; /* Not WPA or Dynamic WEP */
2830
2831 /* Pairwise and Group ciphers (only relevant for WPA/RSN) */
(18) Event cond_true: |
Condition "wpa_psk", taking true branch |
2832 if (wpa_psk || wpa_eap) {
2833 fill_wpa_ciphers (ifcfg, wsec, FALSE, adhoc);
2834 fill_wpa_ciphers (ifcfg, wsec, TRUE, adhoc);
2835 }
2836
2837 /* WPA and/or RSN */
(19) Event cond_true: |
Condition "adhoc", taking true branch |
2838 if (adhoc) {
2839 /* Ad-Hoc mode only supports WPA proto for now */
2840 nm_setting_wireless_security_add_proto (wsec, "wpa");
(20) Event if_fallthrough: |
Falling through to end of if statement |
2841 } else {
2842 char *allow_wpa, *allow_rsn;
2843
2844 allow_wpa = svGetValue (ifcfg, "WPA_ALLOW_WPA", FALSE);
2845 allow_rsn = svGetValue (ifcfg, "WPA_ALLOW_WPA2", FALSE);
2846
2847 if (allow_wpa && svTrueValue (ifcfg, "WPA_ALLOW_WPA", TRUE))
2848 nm_setting_wireless_security_add_proto (wsec, "wpa");
2849 if (allow_rsn && svTrueValue (ifcfg, "WPA_ALLOW_WPA2", TRUE))
2850 nm_setting_wireless_security_add_proto (wsec, "rsn");
2851
2852 /* If neither WPA_ALLOW_WPA or WPA_ALLOW_WPA2 were present, default
2853 * to both WPA and RSN allowed.
2854 */
2855 if (!allow_wpa && !allow_rsn && !ieee8021x) {
2856 nm_setting_wireless_security_add_proto (wsec, "wpa");
2857 nm_setting_wireless_security_add_proto (wsec, "rsn");
2858 }
2859
2860 g_free (allow_wpa);
2861 g_free (allow_rsn);
(21) Event if_end: |
End of if statement |
2862 }
2863
2864 if (!strcmp (value, "WPA-PSK")) {
2865 NMSettingSecretFlags psk_flags;
2866
2867 psk_flags = read_secret_flags (ifcfg, "WPA_PSK_FLAGS");
2868 g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_PSK_FLAGS, psk_flags, NULL);
2869
2870 /* Read PSK if it's system-owned */
2871 if (psk_flags == NM_SETTING_SECRET_FLAG_NONE) {
2872 psk = parse_wpa_psk (ifcfg, file, ssid, error);
2873 if (psk) {
2874 g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_PSK, psk, NULL);
2875 g_free (psk);
2876 }
2877 }
2878
2879 if (adhoc)
2880 g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-none", NULL);
2881 else
2882 g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-psk", NULL);
2883 } else if (!strcmp (value, "WPA-EAP") || !strcmp (value, "IEEE8021X")) {
2884 /* Adhoc mode is mutually exclusive with any 802.1x-based authentication */
2885 if (adhoc) {
2886 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2887 "Ad-Hoc mode cannot be used with KEY_MGMT type '%s'", value);
2888 goto error;
2889 }
2890
2891 *s_8021x = fill_8021x (ifcfg, file, value, TRUE, error);
2892 if (!*s_8021x)
2893 goto error;
2894
2895 lower = g_ascii_strdown (value, -1);
2896 g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, lower, NULL);
2897 g_free (lower);
2898 } else {
2899 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2900 "Unknown wireless KEY_MGMT type '%s'", value);
2901 goto error;
2902 }
2903
2904 g_free (value);
2905 return (NMSetting *) wsec;
2906
2907 error:
2908 g_free (value);
2909 if (wsec)
2910 g_object_unref (wsec);
2911 return NULL;
2912 }
2913
2914 static NMSetting *
2915 make_leap_setting (shvarFile *ifcfg,
2916 const char *file,
2917 GError **error)
2918 {
2919 NMSettingWirelessSecurity *wsec;
2920 shvarFile *keys_ifcfg;
2921 char *value;
2922 NMSettingSecretFlags flags;
2923
2924 wsec = NM_SETTING_WIRELESS_SECURITY (nm_setting_wireless_security_new ());
2925
2926 value = svGetValue (ifcfg, "KEY_MGMT", FALSE);
2927 if (!value || strcmp (value, "IEEE8021X"))
2928 goto error; /* Not LEAP */
2929
2930 g_free (value);
2931 value = svGetValue (ifcfg, "SECURITYMODE", FALSE);
2932 if (!value || strcasecmp (value, "leap"))
2933 goto error; /* Not LEAP */
2934
2935 g_free (value);
2936
2937 flags = read_secret_flags (ifcfg, "IEEE_8021X_PASSWORD_FLAGS");
2938 g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD_FLAGS, flags, NULL);
2939
2940 /* Read LEAP password if it's system-owned */
2941 if (flags == NM_SETTING_SECRET_FLAG_NONE) {
2942 value = svGetValue (ifcfg, "IEEE_8021X_PASSWORD", FALSE);
2943 if (!value) {
2944 /* Try to get keys from the "shadow" key file */
2945 keys_ifcfg = utils_get_keys_ifcfg (file, FALSE);
2946 if (keys_ifcfg) {
2947 value = svGetValue (keys_ifcfg, "IEEE_8021X_PASSWORD", FALSE);
2948 svCloseFile (keys_ifcfg);
2949 }
2950 }
2951 if (value && strlen (value))
2952 g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD, value, NULL);
2953 g_free (value);
2954 }
2955
2956 value = svGetValue (ifcfg, "IEEE_8021X_IDENTITY", FALSE);
2957 if (!value || !strlen (value)) {
2958 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
2959 "Missing LEAP identity");
2960 goto error;
2961 }
2962 g_object_set (wsec, NM_SETTING_WIRELESS_SECURITY_LEAP_USERNAME, value, NULL);
2963 g_free (value);
2964
2965 g_object_set (wsec,
2966 NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x",
2967 NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "leap",
2968 NULL);
2969
2970 return (NMSetting *) wsec;
2971
2972 error:
2973 g_free (value);
2974 if (wsec)
2975 g_object_unref (wsec);
2976 return NULL;
2977 }
2978
2979 static NMSetting *
2980 make_wireless_security_setting (shvarFile *ifcfg,
2981 const char *file,
2982 const GByteArray *ssid,
2983 gboolean adhoc,
2984 NMSetting8021x **s_8021x,
2985 GError **error)
2986 {
2987 NMSetting *wsec;
2988
2989 if (!adhoc) {
2990 wsec = make_leap_setting (ifcfg, file, error);
2991 if (wsec)
2992 return wsec;
2993 else if (*error)
2994 return NULL;
2995 }
2996
2997 wsec = make_wpa_setting (ifcfg, file, ssid, adhoc, s_8021x, error);
2998 if (wsec)
2999 return wsec;
3000 else if (*error)
3001 return NULL;
3002
3003 wsec = make_wep_setting (ifcfg, file, error);
3004 if (wsec)
3005 return wsec;
3006 else if (*error)
3007 return NULL;
3008
3009 return NULL; /* unencrypted */
3010 }
3011
3012 static NMSetting *
3013 make_wireless_setting (shvarFile *ifcfg,
3014 gboolean nm_controlled,
3015 char **unmanaged,
3016 GError **error)
3017 {
3018 NMSettingWireless *s_wireless;
3019 GByteArray *array = NULL;
3020 GSList *macaddr_blacklist = NULL;
3021 char *value;
3022
3023 s_wireless = NM_SETTING_WIRELESS (nm_setting_wireless_new ());
3024
3025 if (read_mac_address (ifcfg, "HWADDR", ARPHRD_ETHER, &array, error)) {
3026 if (array) {
3027 g_object_set (s_wireless, NM_SETTING_WIRELESS_MAC_ADDRESS, array, NULL);
3028
3029 if (!nm_controlled) {
3030 *unmanaged = g_strdup_printf ("mac:%02x:%02x:%02x:%02x:%02x:%02x",
3031 array->data[0], array->data[1], array->data[2],
3032 array->data[3], array->data[4], array->data[5]);
3033 }
3034
3035 g_byte_array_free (array, TRUE);
3036 }
3037 } else {
3038 g_object_unref (s_wireless);
3039 return NULL;
3040 }
3041
3042 array = NULL;
3043 if (read_mac_address (ifcfg, "MACADDR", ARPHRD_ETHER, &array, error)) {
3044 if (array) {
3045 g_object_set (s_wireless, NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS, array, NULL);
3046 g_byte_array_free (array, TRUE);
3047 }
3048 } else {
3049 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: %s", (*error)->message);
3050 g_clear_error (error);
3051 }
3052
3053 value = svGetValue (ifcfg, "HWADDR_BLACKLIST", FALSE);
3054 if (value) {
3055 char **list = NULL, **iter;
3056 struct ether_addr addr;
3057
3058 list = g_strsplit_set (value, " \t", 0);
3059 for (iter = list; iter && *iter; iter++) {
3060 if (**iter == '\0')
3061 continue;
3062 if (!ether_aton_r (*iter, &addr)) {
3063 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: invalid MAC in HWADDR_BLACKLIST '%s'", *iter);
3064 continue;
3065 }
3066 macaddr_blacklist = g_slist_prepend (macaddr_blacklist, *iter);
3067 }
3068 if (macaddr_blacklist) {
3069 macaddr_blacklist = g_slist_reverse (macaddr_blacklist);
3070 g_object_set (s_wireless, NM_SETTING_WIRELESS_MAC_ADDRESS_BLACKLIST, macaddr_blacklist, NULL);
3071 g_slist_free (macaddr_blacklist);
3072 }
3073 g_free (value);
3074 g_strfreev (list);
3075 }
3076
3077 value = svGetValue (ifcfg, "ESSID", TRUE);
3078 if (value) {
3079 gsize ssid_len = 0, value_len = strlen (value);
3080 char *p = value, *tmp;
3081 char buf[33];
3082
3083 ssid_len = value_len;
3084 if ( (value_len >= 2)
3085 && (value[0] == '"')
3086 && (value[value_len - 1] == '"')) {
3087 /* Strip the quotes and unescape */
3088 p = value + 1;
3089 value[value_len - 1] = '\0';
3090 svUnescape (p);
3091 ssid_len = strlen (p);
3092 } else if ((value_len > 2) && (strncmp (value, "0x", 2) == 0)) {
3093 /* Hex representation */
3094 if (value_len % 2) {
3095 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
3096 "Invalid SSID '%s' size (looks like hex but length not multiple of 2)",
3097 value);
3098 g_free (value);
3099 goto error;
3100 }
3101
3102 p = value + 2;
3103 while (*p) {
3104 if (!g_ascii_isxdigit (*p)) {
3105 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
3106 "Invalid SSID '%s' character (looks like hex SSID but '%c' isn't a hex digit)",
3107 value, *p);
3108 g_free (value);
3109 goto error;
3110 }
3111 p++;
3112 }
3113
3114 tmp = nm_utils_hexstr2bin (value + 2, value_len - 2);
3115 ssid_len = (value_len - 2) / 2;
3116 memcpy (buf, tmp, ssid_len);
3117 p = &buf[0];
3118 g_free (tmp);
3119 }
3120
3121 if (ssid_len > 32 || ssid_len == 0) {
3122 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
3123 "Invalid SSID '%s' (size %zu not between 1 and 32 inclusive)",
3124 value, ssid_len);
3125 g_free (value);
3126 goto error;
3127 }
3128
3129 array = g_byte_array_sized_new (ssid_len);
3130 g_byte_array_append (array, (const guint8 *) p, ssid_len);
3131 g_object_set (s_wireless, NM_SETTING_WIRELESS_SSID, array, NULL);
3132 g_byte_array_free (array, TRUE);
3133 g_free (value);
3134 } else {
3135 /* Only fail on lack of SSID if device is managed */
3136 if (nm_controlled) {
3137 g_set_error (error, IFCFG_PLUGIN_ERROR, 0, "Missing SSID");
3138 goto error;
3139 }
3140 }
3141
3142 if (!nm_controlled)
3143 goto done;
3144
3145 value = svGetValue (ifcfg, "MODE", FALSE);
3146 if (value) {
3147 char *lcase;
3148 const char *mode = NULL;
3149
3150 lcase = g_ascii_strdown (value, -1);
3151 g_free (value);
3152
3153 if (!strcmp (lcase, "ad-hoc")) {
3154 mode = "adhoc";
3155 } else if (!strcmp (lcase, "managed") || !strcmp (lcase, "auto")) {
3156 mode = "infrastructure";
3157 } else {
3158 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
3159 "Invalid mode '%s' (not 'Ad-Hoc', 'Managed', or 'Auto')",
3160 lcase);
3161 g_free (lcase);
3162 goto error;
3163 }
3164 g_free (lcase);
3165
3166 g_object_set (s_wireless, NM_SETTING_WIRELESS_MODE, mode, NULL);
3167 }
3168
3169 value = svGetValue (ifcfg, "BSSID", FALSE);
3170 if (value) {
3171 GByteArray *bssid;
3172
3173 bssid = nm_utils_hwaddr_atoba (value, ARPHRD_ETHER);
3174 if (!bssid) {
3175 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
3176 "Invalid BSSID '%s'", value);
3177 g_free (value);
3178 goto error;
3179 }
3180
3181 g_object_set (s_wireless, NM_SETTING_WIRELESS_BSSID, bssid, NULL);
3182 g_byte_array_free (bssid, TRUE);
3183 g_free (value);
3184 }
3185
3186 value = svGetValue (ifcfg, "CHANNEL", FALSE);
3187 if (value) {
3188 long int chan;
3189
3190 errno = 0;
3191 chan = strtol (value, NULL, 10);
3192 if (errno || chan <= 0 || chan > 196) {
3193 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
3194 "Invalid wireless channel '%s'", value);
3195 g_free (value);
3196 goto error;
3197 }
3198 g_object_set (s_wireless, NM_SETTING_WIRELESS_CHANNEL, (guint32) chan, NULL);
3199 if (chan > 14)
3200 g_object_set (s_wireless, NM_SETTING_WIRELESS_BAND, "a", NULL);
3201 else
3202 g_object_set (s_wireless, NM_SETTING_WIRELESS_BAND, "bg", NULL);
3203 g_free (value);
3204 }
3205
3206 value = svGetValue (ifcfg, "MTU", FALSE);
3207 if (value) {
3208 long int mtu;
3209
3210 errno = 0;
3211 mtu = strtol (value, NULL, 10);
3212 if (errno || mtu < 0 || mtu > 50000) {
3213 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
3214 "Invalid wireless MTU '%s'", value);
3215 g_free (value);
3216 goto error;
3217 }
3218 g_object_set (s_wireless, NM_SETTING_WIRELESS_MTU, (guint32) mtu, NULL);
3219 g_free (value);
3220 }
3221
3222 done:
3223 return NM_SETTING (s_wireless);
3224
3225 error:
3226 if (s_wireless)
3227 g_object_unref (s_wireless);
3228 return NULL;
3229 }
3230
3231 static NMConnection *
3232 wireless_connection_from_ifcfg (const char *file,
3233 shvarFile *ifcfg,
3234 gboolean nm_controlled,
3235 char **unmanaged,
3236 GError **error)
3237 {
3238 NMConnection *connection = NULL;
3239 NMSetting *con_setting = NULL;
3240 NMSetting *wireless_setting = NULL;
3241 NMSetting8021x *s_8021x = NULL;
3242 const GByteArray *ssid;
3243 NMSetting *security_setting = NULL;
3244 char *printable_ssid = NULL;
3245 const char *mode;
3246 gboolean adhoc = FALSE;
3247
3248 g_return_val_if_fail (file != NULL, NULL);
3249 g_return_val_if_fail (ifcfg != NULL, NULL);
3250 g_return_val_if_fail (error != NULL, NULL);
3251 g_return_val_if_fail (*error == NULL, NULL);
3252
3253 connection = nm_connection_new ();
3254
3255 /* Wireless */
3256 wireless_setting = make_wireless_setting (ifcfg, nm_controlled, unmanaged, error);
3257 if (!wireless_setting) {
3258 g_object_unref (connection);
3259 return NULL;
3260 }
3261 nm_connection_add_setting (connection, wireless_setting);
3262
3263 ssid = nm_setting_wireless_get_ssid (NM_SETTING_WIRELESS (wireless_setting));
3264 if (ssid)
3265 printable_ssid = nm_utils_ssid_to_utf8 (ssid);
3266 else
3267 printable_ssid = g_strdup_printf ("unmanaged");
3268
3269 if (nm_controlled) {
3270 mode = nm_setting_wireless_get_mode (NM_SETTING_WIRELESS (wireless_setting));
3271 if (mode && !strcmp (mode, "adhoc"))
3272 adhoc = TRUE;
3273
3274 /* Wireless security */
3275 security_setting = make_wireless_security_setting (ifcfg, file, ssid, adhoc, &s_8021x, error);
3276 if (*error) {
3277 g_free (printable_ssid);
3278 g_object_unref (connection);
3279 return NULL;
3280 }
3281 if (security_setting) {
3282 nm_connection_add_setting (connection, security_setting);
3283 if (s_8021x)
3284 nm_connection_add_setting (connection, NM_SETTING (s_8021x));
3285 }
3286 }
3287
3288 /* Connection */
3289 con_setting = make_connection_setting (file, ifcfg,
3290 NM_SETTING_WIRELESS_SETTING_NAME,
3291 printable_ssid, NULL);
3292 g_free (printable_ssid);
3293 if (!con_setting) {
3294 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
3295 "Failed to create connection setting.");
3296 g_object_unref (connection);
3297 return NULL;
3298 }
3299 nm_connection_add_setting (connection, con_setting);
3300
3301 /* Don't verify if unmanaged since we may not have an SSID or whatever */
3302 if (nm_controlled) {
3303 if (!nm_connection_verify (connection, error)) {
3304 g_object_unref (connection);
3305 return NULL;
3306 }
3307 }
3308
3309 return connection;
3310 }
3311
3312 static NMSetting *
3313 make_wired_setting (shvarFile *ifcfg,
3314 const char *file,
3315 gboolean nm_controlled,
3316 char **unmanaged,
3317 NMSetting8021x **s_8021x,
3318 GError **error)
3319 {
3320 NMSettingWired *s_wired;
3321 char *value = NULL;
3322 int mtu;
3323 GByteArray *mac = NULL;
3324 GSList *macaddr_blacklist = NULL;
3325 char *nettype;
3326
3327 s_wired = NM_SETTING_WIRED (nm_setting_wired_new ());
3328
3329 value = svGetValue (ifcfg, "MTU", FALSE);
3330 if (value) {
3331 if (get_int (value, &mtu)) {
3332 if (mtu >= 0 && mtu < 65536)
3333 g_object_set (s_wired, NM_SETTING_WIRED_MTU, mtu, NULL);
3334 } else {
3335 /* Shouldn't be fatal... */
3336 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: invalid MTU '%s'", value);
3337 }
3338 g_free (value);
3339 }
3340
3341 if (read_mac_address (ifcfg, "HWADDR", ARPHRD_ETHER, &mac, error)) {
3342 if (mac) {
3343 g_object_set (s_wired, NM_SETTING_WIRED_MAC_ADDRESS, mac, NULL);
3344
3345 if (!nm_controlled) {
3346 *unmanaged = g_strdup_printf ("mac:%02x:%02x:%02x:%02x:%02x:%02x",
3347 mac->data[0], mac->data[1], mac->data[2],
3348 mac->data[3], mac->data[4], mac->data[5]);
3349 }
3350
3351 g_byte_array_free (mac, TRUE);
3352 }
3353 } else {
3354 g_object_unref (s_wired);
3355 return NULL;
3356 }
3357
3358 value = svGetValue (ifcfg, "SUBCHANNELS", FALSE);
3359 if (value) {
3360 const char *p = value;
3361 gboolean success = TRUE;
3362 char **chans = NULL;
3363
3364 /* basic sanity checks */
3365 while (*p) {
3366 if (!g_ascii_isxdigit (*p) && (*p != ',') && (*p != '.')) {
3367 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: invalid SUBCHANNELS '%s'", value);
3368 success = FALSE;
3369 break;
3370 }
3371 p++;
3372 }
3373
3374 if (success) {
3375 guint32 num_chans;
3376
3377 chans = g_strsplit_set (value, ",", 0);
3378 num_chans = g_strv_length (chans);
3379 if (num_chans < 2 || num_chans > 3) {
3380 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: invalid SUBCHANNELS '%s' (%d channels, 2 or 3 expected)",
3381 value, g_strv_length (chans));
3382 } else {
3383 GPtrArray *array = g_ptr_array_sized_new (num_chans);
3384
3385 g_ptr_array_add (array, chans[0]);
3386 g_ptr_array_add (array, chans[1]);
3387 if (num_chans == 3)
3388 g_ptr_array_add (array, chans[2]);
3389
3390 g_object_set (s_wired, NM_SETTING_WIRED_S390_SUBCHANNELS, array, NULL);
3391 g_ptr_array_free (array, TRUE);
3392
3393 /* set the unmanaged spec too */
3394 if (!nm_controlled && !*unmanaged)
3395 *unmanaged = g_strdup_printf ("s390-subchannels:%s", value);
3396 }
3397 g_strfreev (chans);
3398 }
3399 g_free (value);
3400 }
3401
3402 value = svGetValue (ifcfg, "PORTNAME", FALSE);
3403 if (value && strlen (value)) {
3404 nm_setting_wired_add_s390_option (s_wired, "portname", value);
3405 }
3406 g_free (value);
3407
3408 value = svGetValue (ifcfg, "CTCPROT", FALSE);
3409 if (value && strlen (value))
3410 nm_setting_wired_add_s390_option (s_wired, "ctcprot", value);
3411 g_free (value);
3412
3413 nettype = svGetValue (ifcfg, "NETTYPE", FALSE);
3414 if (nettype && strlen (nettype)) {
3415 if (!strcmp (nettype, "qeth") || !strcmp (nettype, "lcs") || !strcmp (nettype, "ctc"))
3416 g_object_set (s_wired, NM_SETTING_WIRED_S390_NETTYPE, nettype, NULL);
3417 else
3418 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: unknown s390 NETTYPE '%s'", nettype);
3419 }
3420 g_free (nettype);
3421
3422 value = svGetValue (ifcfg, "OPTIONS", FALSE);
3423 if (value && strlen (value)) {
3424 char **options, **iter;
3425
3426 iter = options = g_strsplit_set (value, " ", 0);
3427 while (iter && *iter) {
3428 char *equals = strchr (*iter, '=');
3429 gboolean valid = FALSE;
3430
3431 if (equals) {
3432 *equals = '\0';
3433 valid = nm_setting_wired_add_s390_option (s_wired, *iter, equals + 1);
3434 }
3435 if (!valid)
3436 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: invalid s390 OPTION '%s'", *iter);
3437 iter++;
3438 }
3439 g_strfreev (options);
3440 }
3441 g_free (value);
3442
3443 mac = NULL;
3444 if (read_mac_address (ifcfg, "MACADDR", ARPHRD_ETHER, &mac, error)) {
3445 if (mac) {
3446 g_object_set (s_wired, NM_SETTING_WIRED_CLONED_MAC_ADDRESS, mac, NULL);
3447 g_byte_array_free (mac, TRUE);
3448 }
3449 } else {
3450 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: %s", (*error)->message);
3451 g_clear_error (error);
3452 }
3453
3454 value = svGetValue (ifcfg, "HWADDR_BLACKLIST", FALSE);
3455 if (value) {
3456 char **list = NULL, **iter;
3457 struct ether_addr addr;
3458
3459 list = g_strsplit_set (value, " \t", 0);
3460 for (iter = list; iter && *iter; iter++) {
3461 if (**iter == '\0')
3462 continue;
3463 if (!ether_aton_r (*iter, &addr)) {
3464 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: invalid MAC in HWADDR_BLACKLIST '%s'", *iter);
3465 continue;
3466 }
3467 macaddr_blacklist = g_slist_prepend (macaddr_blacklist, *iter);
3468 }
3469 if (macaddr_blacklist) {
3470 macaddr_blacklist = g_slist_reverse (macaddr_blacklist);
3471 g_object_set (s_wired, NM_SETTING_WIRED_MAC_ADDRESS_BLACKLIST, macaddr_blacklist, NULL);
3472 g_slist_free (macaddr_blacklist);
3473 }
3474 g_free (value);
3475 g_strfreev (list);
3476 }
3477
3478 value = svGetValue (ifcfg, "KEY_MGMT", FALSE);
3479 if (value) {
3480 if (!strcmp (value, "IEEE8021X")) {
3481 *s_8021x = fill_8021x (ifcfg, file, value, FALSE, error);
3482 if (!*s_8021x)
3483 goto error;
3484 } else {
3485 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
3486 "Unknown wired KEY_MGMT type '%s'", value);
3487 goto error;
3488 }
3489 g_free (value);
3490 }
3491
3492 return (NMSetting *) s_wired;
3493
3494 error:
3495 g_free (value);
3496 g_object_unref (s_wired);
3497 return NULL;
3498 }
3499
3500 static NMConnection *
3501 wired_connection_from_ifcfg (const char *file,
3502 shvarFile *ifcfg,
3503 gboolean nm_controlled,
3504 char **unmanaged,
3505 GError **error)
3506 {
3507 NMConnection *connection = NULL;
3508 NMSetting *con_setting = NULL;
3509 NMSetting *wired_setting = NULL;
3510 NMSetting8021x *s_8021x = NULL;
3511
3512 g_return_val_if_fail (file != NULL, NULL);
3513 g_return_val_if_fail (ifcfg != NULL, NULL);
3514
3515 connection = nm_connection_new ();
3516
3517 con_setting = make_connection_setting (file, ifcfg, NM_SETTING_WIRED_SETTING_NAME, NULL, NULL);
3518 if (!con_setting) {
3519 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
3520 "Failed to create connection setting.");
3521 g_object_unref (connection);
3522 return NULL;
3523 }
3524 check_if_bond_slave (ifcfg, NM_SETTING_CONNECTION (con_setting));
3525 check_if_team_slave (ifcfg, NM_SETTING_CONNECTION (con_setting));
3526 nm_connection_add_setting (connection, con_setting);
3527
3528 wired_setting = make_wired_setting (ifcfg, file, nm_controlled, unmanaged, &s_8021x, error);
3529 if (!wired_setting) {
3530 g_object_unref (connection);
3531 return NULL;
3532 }
3533 nm_connection_add_setting (connection, wired_setting);
3534
3535 if (s_8021x)
3536 nm_connection_add_setting (connection, NM_SETTING (s_8021x));
3537
3538 if (!nm_connection_verify (connection, error)) {
3539 g_object_unref (connection);
3540 return NULL;
3541 }
3542
3543 return connection;
3544 }
3545
3546 static gboolean
3547 parse_infiniband_p_key (shvarFile *ifcfg,
3548 int *out_p_key,
3549 char **out_parent,
3550 GError **error)
3551 {
3552 char *device = NULL, *physdev = NULL, *pkey_id = NULL, *end;
3553 char *ifname = NULL;
3554 guint32 id;
3555 gboolean ret = FALSE;
3556
3557 device = svGetValue (ifcfg, "DEVICE", FALSE);
3558 if (!device) {
3559 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " InfiniBand connection specified PKEY but not DEVICE");
3560 goto done;
3561 }
3562
3563 physdev = svGetValue (ifcfg, "PHYSDEV", FALSE);
3564 if (!physdev) {
3565 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " InfiniBand connection specified PKEY but not PHYSDEV");
3566 goto done;
3567 }
3568
3569 pkey_id = svGetValue (ifcfg, "PKEY_ID", FALSE);
3570 if (!pkey_id) {
3571 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " InfiniBand connection specified PKEY but not PKEY_ID");
3572 goto done;
3573 }
3574
3575 if (g_str_has_prefix (pkey_id, "0x"))
3576 id = strtoul (pkey_id, &end, 16);
3577 else if (!g_str_has_prefix (pkey_id, "0"))
3578 id = strtoul (pkey_id, &end, 10);
3579 else
3580 end = pkey_id;
3581 if (end == pkey_id || *end || id > 0xFFFF) {
3582 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " invalid InfiniBand PKEY_ID '%s'", pkey_id);
3583 goto done;
3584 }
3585 id = (id | 0x8000);
3586
3587 ifname = g_strdup_printf ("%s.%04x", physdev, id);
3588 if (strcmp (device, ifname) != 0) {
3589 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " InfiniBand DEVICE (%s) does not match PHYSDEV+PKEY_ID (%s)",
3590 device, ifname);
3591 goto done;
3592 }
3593
3594 *out_p_key = id;
3595 *out_parent = g_strdup (physdev);
3596 ret = TRUE;
3597
3598 done:
3599 g_free (device);
3600 g_free (physdev);
3601 g_free (pkey_id);
3602 g_free (ifname);
3603
3604 if (!ret) {
3605 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
3606 "Failed to create InfiniBand setting.");
3607 }
3608 return ret;
3609 }
3610
3611
3612 static NMSetting *
3613 make_infiniband_setting (shvarFile *ifcfg,
3614 const char *file,
3615 gboolean nm_controlled,
3616 char **unmanaged,
3617 GError **error)
3618 {
3619 NMSettingInfiniband *s_infiniband;
3620 char *value = NULL;
3621 GByteArray *mac = NULL;
3622 int mtu;
3623
3624 s_infiniband = NM_SETTING_INFINIBAND (nm_setting_infiniband_new ());
3625
3626 value = svGetValue (ifcfg, "MTU", FALSE);
3627 if (value) {
3628 if (get_int (value, &mtu)) {
3629 if (mtu >= 0 && mtu < 65536)
3630 g_object_set (s_infiniband, NM_SETTING_INFINIBAND_MTU, mtu, NULL);
3631 } else {
3632 /* Shouldn't be fatal... */
3633 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: invalid MTU '%s'", value);
3634 }
3635 g_free (value);
3636 }
3637
3638 if (read_mac_address (ifcfg, "HWADDR", ARPHRD_INFINIBAND, &mac, error)) {
3639 if (mac) {
3640 g_object_set (s_infiniband, NM_SETTING_INFINIBAND_MAC_ADDRESS, mac, NULL);
3641
3642 if (!nm_controlled) {
3643 char *mac_str = nm_utils_hwaddr_ntoa (mac->data, ARPHRD_INFINIBAND);
3644 *unmanaged = g_strdup_printf ("mac:%s", mac_str);
3645 g_free (mac_str);
3646 }
3647
3648 g_byte_array_free (mac, TRUE);
3649 }
3650 } else {
3651 g_object_unref (s_infiniband);
3652 return NULL;
3653 }
3654
3655 if (svTrueValue (ifcfg, "CONNECTED_MODE", FALSE))
3656 g_object_set (s_infiniband, NM_SETTING_INFINIBAND_TRANSPORT_MODE, "connected", NULL);
3657 else
3658 g_object_set (s_infiniband, NM_SETTING_INFINIBAND_TRANSPORT_MODE, "datagram", NULL);
3659
3660 if (svTrueValue (ifcfg, "PKEY", FALSE)) {
3661 int p_key;
3662 char *parent;
3663
3664 if (!parse_infiniband_p_key (ifcfg, &p_key, &parent, error)) {
3665 g_object_unref (s_infiniband);
3666 return NULL;
3667 }
3668
3669 g_object_set (s_infiniband,
3670 NM_SETTING_INFINIBAND_P_KEY, p_key,
3671 NM_SETTING_INFINIBAND_PARENT, parent,
3672 NULL);
3673 }
3674
3675 return (NMSetting *) s_infiniband;
3676 }
3677
3678 static NMConnection *
3679 infiniband_connection_from_ifcfg (const char *file,
3680 shvarFile *ifcfg,
3681 gboolean nm_controlled,
3682 char **unmanaged,
3683 GError **error)
3684 {
3685 NMConnection *connection = NULL;
3686 NMSetting *con_setting = NULL;
3687 NMSetting *infiniband_setting = NULL;
3688
3689 g_return_val_if_fail (file != NULL, NULL);
3690 g_return_val_if_fail (ifcfg != NULL, NULL);
3691
3692 connection = nm_connection_new ();
3693
3694 con_setting = make_connection_setting (file, ifcfg, NM_SETTING_INFINIBAND_SETTING_NAME, NULL, NULL);
3695 if (!con_setting) {
3696 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
3697 "Failed to create connection setting.");
3698 g_object_unref (connection);
3699 return NULL;
3700 }
3701 check_if_bond_slave (ifcfg, NM_SETTING_CONNECTION (con_setting));
3702 check_if_team_slave (ifcfg, NM_SETTING_CONNECTION (con_setting));
3703 nm_connection_add_setting (connection, con_setting);
3704
3705 infiniband_setting = make_infiniband_setting (ifcfg, file, nm_controlled, unmanaged, error);
3706 if (!infiniband_setting) {
3707 g_object_unref (connection);
3708 return NULL;
3709 }
3710 nm_connection_add_setting (connection, infiniband_setting);
3711
3712 if (!nm_connection_verify (connection, error)) {
3713 g_object_unref (connection);
3714 return NULL;
3715 }
3716
3717 return connection;
3718 }
3719
3720 static void
3721 handle_bond_option (NMSettingBond *s_bond,
3722 const char *key,
3723 const char *value)
3724 {
3725 char *sanitized = NULL, *j;
3726 const char *p = value;
3727
3728 /* Remove any quotes or +/- from arp_ip_target */
3729 if (!g_strcmp0 (key, NM_SETTING_BOND_OPTION_ARP_IP_TARGET) && value && value[0]) {
3730 if (*p == '\'' || *p == '"')
3731 p++;
3732 j = sanitized = g_malloc0 (strlen (p) + 1);
3733 while (*p) {
3734 if (*p != '+' && *p != '-' && *p != '\'' && *p != '"')
3735 *j++ = *p;
3736 p++;
3737 }
3738 }
3739
3740 if (!nm_setting_bond_add_option (s_bond, key, sanitized ? sanitized : value))
3741 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: invalid bonding option '%s'", key);
3742 g_free (sanitized);
3743 }
3744
3745 static NMSetting *
3746 make_bond_setting (shvarFile *ifcfg,
3747 const char *file,
3748 gboolean nm_controlled,
3749 char **unmanaged,
3750 GError **error)
3751 {
3752 NMSettingBond *s_bond;
3753 char *value;
3754
3755 s_bond = NM_SETTING_BOND (nm_setting_bond_new ());
3756
3757 value = svGetValue (ifcfg, "DEVICE", FALSE);
3758 if (!value || !strlen (value)) {
3759 g_set_error (error, IFCFG_PLUGIN_ERROR, 0, "mandatory DEVICE keyword missing");
3760 goto error;
3761 }
3762
3763 g_object_set (s_bond, NM_SETTING_BOND_INTERFACE_NAME, value, NULL);
3764 g_free (value);
3765
3766 value = svGetValue (ifcfg, "BONDING_OPTS", FALSE);
3767 if (value) {
3768 char **items, **iter;
3769
3770 items = g_strsplit_set (value, " ", -1);
3771 for (iter = items; iter && *iter; iter++) {
3772 if (strlen (*iter)) {
3773 char **keys, *key, *val;
3774
3775 keys = g_strsplit_set (*iter, "=", 2);
3776 if (keys && *keys) {
3777 key = *keys;
3778 val = *(keys + 1);
3779 if (val && strlen(key) && strlen(val))
3780 handle_bond_option (s_bond, key, val);
3781 }
3782
3783 g_strfreev (keys);
3784 }
3785 }
3786 g_free (value);
3787 g_strfreev (items);
3788 }
3789
3790 return (NMSetting *) s_bond;
3791
3792 error:
3793 g_object_unref (s_bond);
3794 return NULL;
3795 }
3796
3797 static NMConnection *
3798 bond_connection_from_ifcfg (const char *file,
3799 shvarFile *ifcfg,
3800 gboolean nm_controlled,
3801 char **unmanaged,
3802 GError **error)
3803 {
3804 NMConnection *connection = NULL;
3805 NMSetting *con_setting = NULL;
3806 NMSetting *bond_setting = NULL;
3807 NMSetting *wired_setting = NULL;
3808 NMSetting8021x *s_8021x = NULL;
3809
3810 g_return_val_if_fail (file != NULL, NULL);
3811 g_return_val_if_fail (ifcfg != NULL, NULL);
3812
3813 connection = nm_connection_new ();
3814
3815 con_setting = make_connection_setting (file, ifcfg, NM_SETTING_BOND_SETTING_NAME, NULL, _("Bond"));
3816 if (!con_setting) {
3817 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
3818 "Failed to create connection setting.");
3819 g_object_unref (connection);
3820 return NULL;
3821 }
3822 nm_connection_add_setting (connection, con_setting);
3823
3824 bond_setting = make_bond_setting (ifcfg, file, nm_controlled, unmanaged, error);
3825 if (!bond_setting) {
3826 g_object_unref (connection);
3827 return NULL;
3828 }
3829 nm_connection_add_setting (connection, bond_setting);
3830
3831 wired_setting = make_wired_setting (ifcfg, file, nm_controlled, unmanaged, &s_8021x, error);
3832 if (!wired_setting) {
3833 g_object_unref (connection);
3834 return NULL;
3835 }
3836 nm_connection_add_setting (connection, wired_setting);
3837
3838 if (s_8021x)
3839 nm_connection_add_setting (connection, NM_SETTING (s_8021x));
3840
3841 if (!nm_connection_verify (connection, error)) {
3842 g_object_unref (connection);
3843 return NULL;
3844 }
3845
3846 return connection;
3847 }
3848
3849 static NMSetting *
3850 make_team_setting (shvarFile *ifcfg,
3851 const char *file,
3852 gboolean nm_controlled,
3853 char **unmanaged,
3854 GError **error)
3855 {
3856 NMSettingTeam *s_team;
3857 char *value;
3858
3859 s_team = NM_SETTING_TEAM (nm_setting_team_new ());
3860
3861 value = svGetValue (ifcfg, "DEVICE", FALSE);
3862 if (!value || !strlen (value)) {
3863 g_set_error (error, IFCFG_PLUGIN_ERROR, 0, "mandatory DEVICE keyword missing");
3864 goto error;
3865 }
3866
3867 g_object_set (s_team, NM_SETTING_TEAM_INTERFACE_NAME, value, NULL);
3868 g_free (value);
3869
3870 value = svGetValue (ifcfg, "TEAM_CONFIG", FALSE);
3871 if (value) {
3872 g_object_set (s_team, NM_SETTING_TEAM_CONFIG, value, NULL);
3873 g_free (value);
3874 }
3875
3876 return (NMSetting *) s_team;
3877
3878 error:
3879 g_object_unref (s_team);
3880 return NULL;
3881 }
3882
3883 static NMConnection *
3884 team_connection_from_ifcfg (const char *file,
3885 shvarFile *ifcfg,
3886 gboolean nm_controlled,
3887 char **unmanaged,
3888 GError **error)
3889 {
3890 NMConnection *connection = NULL;
3891 NMSetting *con_setting = NULL;
3892 NMSetting *team_setting = NULL;
3893 NMSetting *wired_setting = NULL;
3894 NMSetting8021x *s_8021x = NULL;
3895
3896 g_return_val_if_fail (file != NULL, NULL);
3897 g_return_val_if_fail (ifcfg != NULL, NULL);
3898
3899 connection = nm_connection_new ();
3900
3901 con_setting = make_connection_setting (file, ifcfg, NM_SETTING_TEAM_SETTING_NAME, NULL, _("Team"));
3902 if (!con_setting) {
3903 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
3904 "Failed to create connection setting.");
3905 g_object_unref (connection);
3906 return NULL;
3907 }
3908 nm_connection_add_setting (connection, con_setting);
3909
3910 team_setting = make_team_setting (ifcfg, file, nm_controlled, unmanaged, error);
3911 if (!team_setting) {
3912 g_object_unref (connection);
3913 return NULL;
3914 }
3915 nm_connection_add_setting (connection, team_setting);
3916
3917 wired_setting = make_wired_setting (ifcfg, file, nm_controlled, unmanaged, &s_8021x, error);
3918 if (!wired_setting) {
3919 g_object_unref (connection);
3920 return NULL;
3921 }
3922 nm_connection_add_setting (connection, wired_setting);
3923
3924 if (s_8021x)
3925 nm_connection_add_setting (connection, NM_SETTING (s_8021x));
3926
3927 if (!nm_connection_verify (connection, error)) {
3928 g_object_unref (connection);
3929 return NULL;
3930 }
3931
3932 return connection;
3933 }
3934
3935 typedef void (*BridgeOptFunc) (NMSetting *setting,
3936 gboolean stp,
3937 const char *key,
3938 const char *value);
3939
3940 static void
3941 handle_bridge_option (NMSetting *setting,
3942 gboolean stp,
3943 const char *key,
3944 const char *value)
3945 {
3946 guint32 u = 0;
3947
3948 if (!strcmp (key, "priority")) {
3949 if (stp == FALSE) {
3950 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: 'priority' invalid when STP is disabled");
3951 } else if (get_uint (value, &u))
3952 g_object_set (setting, NM_SETTING_BRIDGE_PRIORITY, u, NULL);
3953 else
3954 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: invalid priority value '%s'", value);
3955 } else if (!strcmp (key, "hello_time")) {
3956 if (stp == FALSE) {
3957 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: 'hello_time' invalid when STP is disabled");
3958 } else if (get_uint (value, &u))
3959 g_object_set (setting, NM_SETTING_BRIDGE_HELLO_TIME, u, NULL);
3960 else
3961 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: invalid hello_time value '%s'", value);
3962 } else if (!strcmp (key, "max_age")) {
3963 if (stp == FALSE) {
3964 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: 'max_age' invalid when STP is disabled");
3965 } else if (get_uint (value, &u))
3966 g_object_set (setting, NM_SETTING_BRIDGE_MAX_AGE, u, NULL);
3967 else
3968 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: invalid max_age value '%s'", value);
3969 } else if (!strcmp (key, "ageing_time")) {
3970 if (get_uint (value, &u))
3971 g_object_set (setting, NM_SETTING_BRIDGE_AGEING_TIME, u, NULL);
3972 else
3973 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: invalid ageing_time value '%s'", value);
3974 } else
3975 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: unhandled bridge option '%s'", key);
3976 }
3977
3978 static void
3979 handle_bridging_opts (NMSetting *setting,
3980 gboolean stp,
3981 const char *value,
3982 BridgeOptFunc func)
3983 {
3984 char **items, **iter;
3985
3986 items = g_strsplit_set (value, " ", -1);
3987 for (iter = items; iter && *iter; iter++) {
3988 if (strlen (*iter)) {
3989 char **keys, *key, *val;
3990
3991 keys = g_strsplit_set (*iter, "=", 2);
3992 if (keys && *keys) {
3993 key = *keys;
3994 val = *(keys + 1);
3995 if (val && strlen(key) && strlen(val))
3996 func (setting, stp, key, val);
3997 }
3998
3999 g_strfreev (keys);
4000 }
4001 }
4002 g_strfreev (items);
4003 }
4004
4005 static NMSetting *
4006 make_bridge_setting (shvarFile *ifcfg,
4007 const char *file,
4008 gboolean nm_controlled,
4009 char **unmanaged,
4010 GError **error)
4011 {
4012 NMSettingBridge *s_bridge;
4013 char *value;
4014 guint32 u;
4015 gboolean stp = FALSE;
4016 gboolean stp_set = FALSE;
4017
4018 s_bridge = NM_SETTING_BRIDGE (nm_setting_bridge_new ());
4019
4020 value = svGetValue (ifcfg, "DEVICE", FALSE);
4021 if (!value || !strlen (value)) {
4022 g_set_error (error, IFCFG_PLUGIN_ERROR, 0, "mandatory DEVICE keyword missing");
4023 goto error;
4024 }
4025
4026 g_object_set (s_bridge, NM_SETTING_BRIDGE_INTERFACE_NAME, value, NULL);
4027 g_free (value);
4028
4029 value = svGetValue (ifcfg, "STP", FALSE);
4030 if (value) {
4031 if (!strcasecmp (value, "on") || !strcasecmp (value, "yes")) {
4032 g_object_set (s_bridge, NM_SETTING_BRIDGE_STP, TRUE, NULL);
4033 stp = TRUE;
4034 stp_set = TRUE;
4035 } else if (!strcasecmp (value, "off") || !strcasecmp (value, "no")) {
4036 g_object_set (s_bridge, NM_SETTING_BRIDGE_STP, FALSE, NULL);
4037 stp_set = TRUE;
4038 } else
4039 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: invalid STP value '%s'", value);
4040 g_free (value);
4041 }
4042
4043 if (!stp_set) {
4044 /* Missing or invalid STP property means "no" */
4045 g_object_set (s_bridge, NM_SETTING_BRIDGE_STP, FALSE, NULL);
4046 }
4047
4048 value = svGetValue (ifcfg, "DELAY", FALSE);
4049 if (value) {
4050 if (stp) {
4051 if (get_uint (value, &u))
4052 g_object_set (s_bridge, NM_SETTING_BRIDGE_FORWARD_DELAY, u, NULL);
4053 else
4054 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: invalid forward delay value '%s'", value);
4055 } else
4056 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: DELAY invalid when STP is disabled");
4057 g_free (value);
4058 }
4059
4060 value = svGetValue (ifcfg, "BRIDGING_OPTS", FALSE);
4061 if (value) {
4062 handle_bridging_opts (NM_SETTING (s_bridge), stp, value, handle_bridge_option);
4063 g_free (value);
4064 }
4065
4066 return (NMSetting *) s_bridge;
4067
4068 error:
4069 g_object_unref (s_bridge);
4070 return NULL;
4071 }
4072
4073 static NMConnection *
4074 bridge_connection_from_ifcfg (const char *file,
4075 shvarFile *ifcfg,
4076 gboolean nm_controlled,
4077 char **unmanaged,
4078 GError **error)
4079 {
4080 NMConnection *connection = NULL;
4081 NMSetting *con_setting = NULL;
4082 NMSetting *bridge_setting = NULL;
4083
4084 g_return_val_if_fail (file != NULL, NULL);
4085 g_return_val_if_fail (ifcfg != NULL, NULL);
4086
4087 connection = nm_connection_new ();
4088
4089 con_setting = make_connection_setting (file, ifcfg, NM_SETTING_BRIDGE_SETTING_NAME, NULL, _("Bridge"));
4090 if (!con_setting) {
4091 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
4092 "Failed to create connection setting.");
4093 g_object_unref (connection);
4094 return NULL;
4095 }
4096 nm_connection_add_setting (connection, con_setting);
4097
4098 bridge_setting = make_bridge_setting (ifcfg, file, nm_controlled, unmanaged, error);
4099 if (!bridge_setting) {
4100 g_object_unref (connection);
4101 return NULL;
4102 }
4103 nm_connection_add_setting (connection, bridge_setting);
4104
4105 if (!nm_connection_verify (connection, error)) {
4106 g_object_unref (connection);
4107 return NULL;
4108 }
4109
4110 return connection;
4111 }
4112
4113 static void
4114 handle_bridge_port_option (NMSetting *setting,
4115 gboolean stp,
4116 const char *key,
4117 const char *value)
4118 {
4119 guint32 u = 0;
4120
4121 if (!strcmp (key, "priority")) {
4122 if (get_uint (value, &u))
4123 g_object_set (setting, NM_SETTING_BRIDGE_PORT_PRIORITY, u, NULL);
4124 else
4125 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: invalid priority value '%s'", value);
4126 } else if (!strcmp (key, "path_cost")) {
4127 if (get_uint (value, &u))
4128 g_object_set (setting, NM_SETTING_BRIDGE_PORT_PATH_COST, u, NULL);
4129 else
4130 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: invalid path_cost value '%s'", value);
4131 } else if (!strcmp (key, "hairpin_mode")) {
4132 if (!strcasecmp (value, "on") || !strcasecmp (value, "yes") || !strcmp (value, "1"))
4133 g_object_set (setting, NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE, TRUE, NULL);
4134 else if (!strcasecmp (value, "off") || !strcasecmp (value, "no"))
4135 g_object_set (setting, NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE, FALSE, NULL);
4136 else
4137 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: invalid hairpin_mode value '%s'", value);
4138 } else
4139 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: unhandled bridge port option '%s'", key);
4140 }
4141
4142 static NMSetting *
4143 make_bridge_port_setting (shvarFile *ifcfg)
4144 {
4145 NMSetting *s_port = NULL;
4146 char *value;
4147
4148 g_return_val_if_fail (ifcfg != NULL, FALSE);
4149
4150 value = svGetValue (ifcfg, "BRIDGE", FALSE);
4151 if (value) {
4152 g_free (value);
4153
4154 s_port = nm_setting_bridge_port_new ();
4155 value = svGetValue (ifcfg, "BRIDGING_OPTS", FALSE);
4156 if (value)
4157 handle_bridging_opts (s_port, FALSE, value, handle_bridge_port_option);
4158 g_free (value);
4159 }
4160
4161 return s_port;
4162 }
4163
4164 static NMSetting *
4165 make_team_port_setting (shvarFile *ifcfg)
4166 {
4167 NMSetting *s_port = NULL;
4168 char *value;
4169
4170 value = svGetValue (ifcfg, "TEAM_PORT_CONFIG", FALSE);
4171 if (value) {
4172 s_port = nm_setting_team_port_new ();
4173 g_object_set (s_port, NM_SETTING_TEAM_PORT_CONFIG, value, NULL);
4174 g_free (value);
4175 }
4176
4177 return s_port;
4178 }
4179
4180 static gboolean
4181 is_bond_device (const char *name, shvarFile *parsed)
4182 {
4183 g_return_val_if_fail (name != NULL, FALSE);
4184 g_return_val_if_fail (parsed != NULL, FALSE);
4185
4186 if (svTrueValue (parsed, "BONDING_MASTER", FALSE))
4187 return TRUE;
4188
4189 /* XXX: Check for "bond[\d]+"? */
4190
4191 return FALSE;
4192 }
4193
4194 static gboolean
4195 is_vlan_device (const char *name, shvarFile *parsed)
4196 {
4197 g_return_val_if_fail (name != NULL, FALSE);
4198 g_return_val_if_fail (parsed != NULL, FALSE);
4199
4200 if (svTrueValue (parsed, "VLAN", FALSE))
4201 return TRUE;
4202
4203 return FALSE;
4204 }
4205
4206 static void
4207 parse_prio_map_list (NMSettingVlan *s_vlan,
4208 shvarFile *ifcfg,
4209 const char *key,
4210 NMVlanPriorityMap map)
4211 {
4212 char *value;
4213 gchar **list = NULL, **iter;
4214
4215 value = svGetValue (ifcfg, key, FALSE);
4216 if (!value)
4217 return;
4218
4219 list = g_strsplit_set (value, ",", -1);
4220 g_free (value);
4221
4222 for (iter = list; iter && *iter; iter++) {
4223 if (!*iter || !strchr (*iter, ':'))
4224 continue;
4225
4226 if (!nm_setting_vlan_add_priority_str (s_vlan, map, *iter)) {
4227 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: invalid %s priority map item '%s'",
4228 key, *iter);
4229 }
4230 }
4231 g_strfreev (list);
4232 }
4233
4234 static NMSetting *
4235 make_vlan_setting (shvarFile *ifcfg,
4236 const char *file,
4237 gboolean nm_controlled,
4238 char **out_master,
4239 char **unmanaged,
4240 NMSetting8021x **s_8021x,
4241 GError **error)
4242 {
4243 NMSettingVlan *s_vlan = NULL;
4244 char *value = NULL;
4245 char *iface_name = NULL;
4246 char *parent = NULL;
4247 const char *p = NULL;
4248 char *end = NULL;
4249 gint vlan_id = -1;
4250 guint32 vlan_flags = 0;
4251
4252 value = svGetValue (ifcfg, "VLAN_ID", FALSE);
4253 if (value) {
4254 errno = 0;
4255 vlan_id = (gint) g_ascii_strtoll (value, NULL, 10);
4256 if (vlan_id < 0 || vlan_id > 4096 || errno) {
4257 g_set_error (error, IFCFG_PLUGIN_ERROR, 0, "Invalid VLAN_ID '%s'", value);
4258 g_free (value);
4259 return NULL;
4260 }
4261 g_free (value);
4262 }
4263
4264 /* Need DEVICE if we don't have a separate VLAN_ID property */
4265 iface_name = svGetValue (ifcfg, "DEVICE", FALSE);
4266 if (!iface_name && vlan_id < 0) {
4267 g_set_error_literal (error, IFCFG_PLUGIN_ERROR, 0,
4268 "Missing DEVICE property; cannot determine VLAN ID.");
4269 return NULL;
4270 }
4271
4272 s_vlan = NM_SETTING_VLAN (nm_setting_vlan_new ());
4273
4274 /* Parent interface from PHYSDEV takes precedence if it exists */
4275 parent = svGetValue (ifcfg, "PHYSDEV", FALSE);
4276
4277 if (iface_name) {
4278 g_object_set (s_vlan, NM_SETTING_VLAN_INTERFACE_NAME, iface_name, NULL);
4279
4280 p = strchr (iface_name, '.');
4281 if (p) {
4282 /* eth0.43; PHYSDEV is assumed from it if unknown */
4283 if (!parent) {
4284 parent = g_strndup (iface_name, p - iface_name);
4285 if (g_str_has_prefix (parent, "vlan")) {
4286 /* Like initscripts, if no PHYSDEV and we get an obviously
4287 * invalid parent interface from DEVICE, fail.
4288 */
4289 g_free (parent);
4290 parent = NULL;
4291 }
4292 }
4293 p++;
4294 } else {
4295 /* format like vlan43; PHYSDEV or MASTER must be set */
4296 if (g_str_has_prefix (iface_name, "vlan"))
4297 p = iface_name + 4;
4298 }
4299
4300 if (p) {
4301 /* Grab VLAN ID from interface name; this takes precedence over the
4302 * separate VLAN_ID property for backwards compat.
4303 */
4304 vlan_id = (gint) g_ascii_strtoll (p, &end, 10);
4305 if (vlan_id < 0 || vlan_id > 4095 || end == p || *end) {
4306 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
4307 "Failed to determine VLAN ID from DEVICE '%s'",
4308 iface_name);
4309 goto error;
4310 }
4311 }
4312 }
4313
4314 if (vlan_id < 0) {
4315 g_set_error_literal (error, IFCFG_PLUGIN_ERROR, 0,
4316 "Failed to determine VLAN ID from DEVICE or VLAN_ID.");
4317 goto error;
4318 }
4319 g_object_set (s_vlan, NM_SETTING_VLAN_ID, vlan_id, NULL);
4320
4321 if (parent == NULL) {
4322 g_set_error_literal (error, IFCFG_PLUGIN_ERROR, 0,
4323 "Failed to determine VLAN parent from DEVICE or PHYSDEV");
4324 goto error;
4325 }
4326 g_object_set (s_vlan, NM_SETTING_VLAN_PARENT, parent, NULL);
4327
4328 if (svTrueValue (ifcfg, "REORDER_HDR", FALSE))
4329 vlan_flags |= NM_VLAN_FLAG_REORDER_HEADERS;
4330
4331 value = svGetValue (ifcfg, "VLAN_FLAGS", FALSE);
4332 if (value) {
4333 if (g_strstr_len (value, -1, "GVRP"))
4334 vlan_flags |= NM_VLAN_FLAG_GVRP;
4335 if (g_strstr_len (value, -1, "LOOSE_BINDING"))
4336 vlan_flags |= NM_VLAN_FLAG_LOOSE_BINDING;
4337 }
4338
4339 g_object_set (s_vlan, NM_SETTING_VLAN_FLAGS, vlan_flags, NULL);
4340 g_free (value);
4341
4342 parse_prio_map_list (s_vlan, ifcfg, "VLAN_INGRESS_PRIORITY_MAP", NM_VLAN_INGRESS_MAP);
4343 parse_prio_map_list (s_vlan, ifcfg, "VLAN_EGRESS_PRIORITY_MAP", NM_VLAN_EGRESS_MAP);
4344
4345 if (out_master)
4346 *out_master = svGetValue (ifcfg, "MASTER", FALSE);
4347 return (NMSetting *) s_vlan;
4348
4349 error:
4350 g_free (parent);
4351 g_free (iface_name);
4352 g_object_unref (s_vlan);
4353 return NULL;
4354 }
4355
4356 static NMConnection *
4357 vlan_connection_from_ifcfg (const char *file,
4358 shvarFile *ifcfg,
4359 gboolean nm_controlled,
4360 char **unmanaged,
4361 GError **error)
4362 {
4363 NMConnection *connection = NULL;
4364 NMSetting *con_setting = NULL;
4365 NMSetting *wired_setting = NULL;
4366 NMSetting *vlan_setting = NULL;
4367 NMSetting8021x *s_8021x = NULL;
4368 char *master = NULL;
4369
4370 g_return_val_if_fail (file != NULL, NULL);
4371 g_return_val_if_fail (ifcfg != NULL, NULL);
4372
4373 connection = nm_connection_new ();
4374
4375 con_setting = make_connection_setting (file, ifcfg, NM_SETTING_VLAN_SETTING_NAME, NULL, "Vlan");
4376 if (!con_setting) {
4377 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
4378 "Failed to create connection setting.");
4379 g_object_unref (connection);
4380 return NULL;
4381 }
4382 nm_connection_add_setting (connection, con_setting);
4383
4384 vlan_setting = make_vlan_setting (ifcfg, file, nm_controlled, &master, unmanaged, &s_8021x, error);
4385 if (!vlan_setting) {
4386 g_object_unref (connection);
4387 return NULL;
4388 }
4389 nm_connection_add_setting (connection, vlan_setting);
4390
4391 /* Handle master interface or connection */
4392 if (master) {
4393 g_object_set (con_setting, NM_SETTING_CONNECTION_MASTER, master, NULL);
4394 g_object_set (con_setting,
4395 NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_VLAN_SETTING_NAME,
4396 NULL);
4397 g_free (master);
4398 }
4399
4400 wired_setting = make_wired_setting (ifcfg, file, nm_controlled, unmanaged, &s_8021x, error);
4401 if (!wired_setting) {
4402 g_object_unref (connection);
4403 return NULL;
4404 }
4405 nm_connection_add_setting (connection, wired_setting);
4406
4407 if (s_8021x)
4408 nm_connection_add_setting (connection, NM_SETTING (s_8021x));
4409 if (!nm_connection_verify (connection, error)) {
4410 g_object_unref (connection);
4411 return NULL;
4412 }
4413
4414 return connection;
4415 }
4416
4417 static void
4418 ensure_unmanaged (shvarFile *ifcfg,
4419 char **unmanaged)
4420 {
4421 char *value;
4422
4423 if (*unmanaged)
4424 return;
4425
4426 value = svGetValue (ifcfg, "DEVICE", FALSE);
4427 if (value) {
4428 *unmanaged = g_strdup_printf ("interface-name:%s", value);
4429 g_free (value);
4430 return;
4431 }
4432
4433 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: NM_CONTROLLED was false but device was not uniquely identified; device will be managed");
4434 }
4435
4436 char *
4437 uuid_from_file (const char *filename)
4438 {
4439 const char *ifcfg_name = NULL;
4440 shvarFile *ifcfg;
4441 char *uuid;
4442
4443 g_return_val_if_fail (filename != NULL, NULL);
4444
4445 ifcfg_name = utils_get_ifcfg_name (filename, TRUE);
4446 if (!ifcfg_name)
4447 return NULL;
4448
4449 ifcfg = svNewFile (filename);
4450 if (!ifcfg)
4451 return NULL;
4452
4453 /* Try for a UUID key before falling back to hashing the file name */
4454 uuid = svGetValue (ifcfg, "UUID", FALSE);
4455 if (!uuid || !strlen (uuid)) {
4456 g_free (uuid);
4457 uuid = nm_utils_uuid_generate_from_string (ifcfg->fileName);
4458 }
4459
4460 svCloseFile (ifcfg);
4461 return uuid;
4462 }
4463
4464 static void
4465 check_dns_search_domains (shvarFile *ifcfg, NMSetting *s_ip4, NMSetting *s_ip6)
4466 {
4467 if (!s_ip6)
4468 return;
4469
4470 /* If there is no IPv4 config or it doesn't contain DNS searches,
4471 * read DOMAIN and put the domains into IPv6.
4472 */
4473 if (!s_ip4 || nm_setting_ip4_config_get_num_dns_searches (NM_SETTING_IP4_CONFIG (s_ip4)) == 0) {
4474 /* DNS searches */
4475 char *value = svGetValue (ifcfg, "DOMAIN", FALSE);
4476 if (value) {
4477 char **searches = g_strsplit (value, " ", 0);
4478 if (searches) {
4479 char **item;
4480 for (item = searches; *item; item++) {
4481 if (strlen (*item)) {
4482 if (!nm_setting_ip6_config_add_dns_search (NM_SETTING_IP6_CONFIG (s_ip6), *item))
4483 PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: duplicate DNS domain '%s'", *item);
4484 }
4485 }
4486 g_strfreev (searches);
4487 }
4488 g_free (value);
4489 }
4490 }
4491 }
4492
4493 NMConnection *
4494 connection_from_file (const char *filename,
4495 const char *network_file, /* for unit tests only */
4496 const char *test_type, /* for unit tests only */
4497 const char *iscsiadm_path, /* for unit tests only */
4498 char **out_unmanaged,
4499 char **out_keyfile,
4500 char **out_routefile,
4501 char **out_route6file,
4502 GError **error,
4503 gboolean *out_ignore_error)
4504 {
4505 NMConnection *connection = NULL;
4506 shvarFile *parsed;
4507 char *type, *devtype, *nmc = NULL, *bootproto;
4508 NMSetting *s_ip4, *s_ip6, *s_port;
4509 const char *ifcfg_name = NULL;
4510 gboolean nm_controlled = TRUE;
4511 char *unmanaged = NULL;
4512
4513 g_return_val_if_fail (filename != NULL, NULL);
4514 if (out_unmanaged)
4515 g_return_val_if_fail (*out_unmanaged == NULL, NULL);
4516 if (out_keyfile)
4517 g_return_val_if_fail (*out_keyfile == NULL, NULL);
4518 if (out_routefile)
4519 g_return_val_if_fail (*out_routefile == NULL, NULL);
4520 if (out_route6file)
4521 g_return_val_if_fail (*out_route6file == NULL, NULL);
4522
4523 /* Non-NULL only for unit tests; normally use /etc/sysconfig/network */
4524 if (!network_file)
4525 network_file = SYSCONFDIR "/sysconfig/network";
4526
4527 if (!iscsiadm_path)
4528 iscsiadm_path = "/sbin/iscsiadm";
4529
4530 ifcfg_name = utils_get_ifcfg_name (filename, TRUE);
4531 if (!ifcfg_name) {
4532 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
4533 "Ignoring connection '%s' because it's not an ifcfg file.", filename);
4534 return NULL;
4535 }
4536
4537 parsed = svNewFile (filename);
4538 if (!parsed) {
4539 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
4540 "Couldn't parse file '%s'", filename);
4541 return NULL;
4542 }
4543
4544 type = NULL;
4545
4546 devtype = svGetValue (parsed, "DEVICETYPE", FALSE);
4547 if (devtype) {
4548 if (!strcasecmp (devtype, TYPE_TEAM))
4549 type = g_strdup (TYPE_TEAM);
4550 g_free (devtype);
4551 }
4552
4553 if (!type)
4554 type = svGetValue (parsed, "TYPE", FALSE);
4555
4556 if (!type) {
4557 char *device;
4558
4559 device = svGetValue (parsed, "DEVICE", FALSE);
4560 if (!device) {
4561 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
4562 "File '%s' had neither TYPE nor DEVICE keys.", filename);
4563 goto done;
4564 }
4565
4566 if (!strcmp (device, "lo")) {
4567 if (out_ignore_error)
4568 *out_ignore_error = TRUE;
4569 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
4570 "Ignoring loopback device config.");
4571 g_free (device);
4572 goto done;
4573 }
4574
4575 if (!test_type) {
4576 if (is_bond_device (device, parsed))
4577 type = g_strdup (TYPE_BOND);
4578 else if (is_vlan_device (device, parsed))
4579 type = g_strdup (TYPE_VLAN);
4580 /* Test wireless extensions */
4581 else if (wifi_utils_is_wifi (device, NULL))
4582 type = g_strdup (TYPE_WIRELESS);
4583 else
4584 type = g_strdup (TYPE_ETHERNET);
4585 } else {
4586 /* For the unit tests, there won't necessarily be any
4587 * adapters of the connection's type in the system so the
4588 * type can't be tested with ioctls.
4589 */
4590 type = g_strdup (test_type);
4591 }
4592
4593 g_free (device);
4594 } else {
4595 /* Check for IBM s390 CTC devices and call them Ethernet */
4596 if (g_strcmp0 (type, "CTC") == 0) {
4597 g_free (type);
4598 type = g_strdup (TYPE_ETHERNET);
4599 }
4600 }
4601
4602 nmc = svGetValue (parsed, "NM_CONTROLLED", FALSE);
4603 if (nmc) {
4604 char *lower;
4605
4606 lower = g_ascii_strdown (nmc, -1);
4607 g_free (nmc);
4608
4609 if (!strcmp (lower, "no") || !strcmp (lower, "n") || !strcmp (lower, "false"))
4610 nm_controlled = FALSE;
4611 g_free (lower);
4612 }
4613
4614 if (svTrueValue (parsed, "BONDING_MASTER", FALSE) &&
4615 strcasecmp (type, TYPE_BOND)) {
4616 g_set_error (error, IFCFG_PLUGIN_ERROR, 0,
4617 "BONDING_MASTER=yes key only allowed in TYPE=bond connections");
4618 goto done;
4619 }
4620
4621 /* Construct the connection */
4622 if (!strcasecmp (type, TYPE_ETHERNET))
4623 connection = wired_connection_from_ifcfg (filename, parsed, nm_controlled, &unmanaged, error);
4624 else if (!strcasecmp (type, TYPE_WIRELESS))
4625 connection = wireless_connection_from_ifcfg (filename, parsed, nm_controlled, &unmanaged, error);
4626 else if (!strcasecmp (type, TYPE_INFINIBAND))
4627 connection = infiniband_connection_from_ifcfg (filename, parsed, nm_controlled, &unmanaged, error);
4628 else if (!strcasecmp (type, TYPE_BOND))
4629 connection = bond_connection_from_ifcfg (filename, parsed, nm_controlled, &unmanaged, error);
4630 else if (!strcasecmp (type, TYPE_TEAM))
4631 connection = team_connection_from_ifcfg (filename, parsed, nm_controlled, &unmanaged, error);
4632 else if (!strcasecmp (type, TYPE_VLAN))
4633 connection = vlan_connection_from_ifcfg (filename, parsed, nm_controlled, &unmanaged, error);
4634 else if (!strcasecmp (type, TYPE_BRIDGE))
4635 connection = bridge_connection_from_ifcfg (filename, parsed, nm_controlled, &unmanaged, error);
4636 else {
4637 g_set_error (error, IFCFG_PLUGIN_ERROR, 0, "Unknown connection type '%s'", type);
4638 }
4639
4640 if (!nm_controlled)
4641 ensure_unmanaged (parsed, &unmanaged);
4642
4643 g_free (type);
4644
4645 /* Don't bother reading the connection fully if it's unmanaged or ignored */
4646 if (!connection || unmanaged)
4647 goto done;
4648
4649 s_ip6 = make_ip6_setting (parsed, network_file, iscsiadm_path, error);
4650 if (!s_ip6) {
4651 g_object_unref (connection);
4652 connection = NULL;
4653 goto done;
4654 } else
4655 nm_connection_add_setting (connection, s_ip6);
4656
4657 s_ip4 = make_ip4_setting (parsed, network_file, iscsiadm_path, error);
4658 if (!s_ip4) {
4659 g_object_unref (connection);
4660 connection = NULL;
4661 goto done;
4662 } else
4663 nm_connection_add_setting (connection, s_ip4);
4664
4665 /* There is only one DOMAIN variable and it is read and put to IPv4 config
4666 * But if IPv4 is disabled or the config fails for some reason, we read
4667 * DOMAIN and put the values into IPv6 config instead.
4668 */
4669 check_dns_search_domains (parsed, s_ip4, s_ip6);
4670
4671 /* Bridge port? */
4672 s_port = make_bridge_port_setting (parsed);
4673 if (s_port)
4674 nm_connection_add_setting (connection, s_port);
4675
4676 /* Team port? */
4677 s_port = make_team_port_setting (parsed);
4678 if (s_port)
4679 nm_connection_add_setting (connection, s_port);
4680
4681 /* iSCSI / ibft connections are read-only since their settings are
4682 * stored in NVRAM and can only be changed in BIOS.
4683 */
4684 bootproto = svGetValue (parsed, "BOOTPROTO", FALSE);
4685 if ( bootproto
4686 && connection
4687 && !g_ascii_strcasecmp (bootproto, "ibft")) {
4688 NMSettingConnection *s_con;
4689
4690 s_con = nm_connection_get_setting_connection (connection);
4691 g_assert (s_con);
4692
4693 g_object_set (G_OBJECT (s_con), NM_SETTING_CONNECTION_READ_ONLY, TRUE, NULL);
4694 }
4695 g_free (bootproto);
4696
4697 nm_utils_normalize_connection (connection, TRUE);
4698
4699 if (!nm_connection_verify (connection, error)) {
4700 g_object_unref (connection);
4701 connection = NULL;
4702 }
4703
4704 if (out_keyfile)
4705 *out_keyfile = utils_get_keys_path (filename);
4706 if (out_routefile)
4707 *out_routefile = utils_get_route_path (filename);
4708 if (out_route6file)
4709 *out_route6file = utils_get_route6_path (filename);
4710
4711 done:
4712 if (out_unmanaged)
4713 *out_unmanaged = unmanaged;
4714 else
4715 g_free (unmanaged);
4716
4717 svCloseFile (parsed);
4718 return connection;
4719 }
4720
4721