From ded7f66ccbc8b98ef6d8a78534df53f1a2108e16 Mon Sep 17 00:00:00 2001
From: Marius Tomaschewski <mt@suse.de>
Date: Wed, 31 Mar 2021 15:23:26 +0200
Subject: [PATCH 1/6] dhcp6: request nis options on sle15 by default


diff --git a/configure.ac b/configure.ac
index 11910aba..4dd3af7e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -35,6 +35,15 @@ if test "x$enable_lldp" = "xyes" ; then
 	AC_DEFINE([NI_ENABLE_LLDP], [], [Enable lldp support])
 fi
 
+# Whether to request NIS option in dhcp6 by default
+AC_ARG_ENABLE([dhcp6-nis],
+	      [AS_HELP_STRING([--disable-dhcp6-nis],
+	       [disable to not request DHCPv6 NIS options by default])],,
+	      [enable_dhcp6_nis=yes])
+if test "x$enable_dhcp6_nis" = "xyes" ; then
+	AC_DEFINE([NI_DHCP6_NIS], [1], [Enable to request DHCPv6 NIS options by default])
+fi
+
 # Whether to use rfc4361 dhcp4 client-id by default
 AC_ARG_ENABLE([dhcp4-rfc4361-cid],
 	      [AS_HELP_STRING([--disable-dhcp4-rfc4361-cid],
diff --git a/src/config.c b/src/config.c
index e3be5736..641c0768 100644
--- a/src/config.c
+++ b/src/config.c
@@ -1775,6 +1775,9 @@ ni_c_binding_get_address(const ni_c_binding_t *binding)
 static unsigned int
 ni_config_addrconf_update_mask_all(void)
 {
+	/*
+	 * Mask of all supported update flags
+	 */
 	static unsigned mask = __NI_ADDRCONF_UPDATE_NONE;
 	if (!mask) {
 		unsigned int i;
@@ -1790,18 +1793,27 @@ ni_config_addrconf_update_mask_all(void)
 static unsigned int
 ni_config_addrconf_update_default(void)
 {
+	/*
+	 * Update flags enabled for static/intrinsic leases by default
+	 */
 	return ni_config_addrconf_update_mask_all();
 }
 
 static unsigned int
 ni_config_addrconf_update_mask_dhcp4(void)
 {
+	/*
+	 * All supported update flags for dhcp4 leases
+	 */
 	return ni_config_addrconf_update_mask_all();
 }
 
 static unsigned int
 ni_config_addrconf_update_dhcp4(void)
 {
+	/*
+	 * Update flags enabled for dhcp4 leases by default
+	 */
 	return	NI_BIT(NI_ADDRCONF_UPDATE_DEFAULT_ROUTE)|
 		NI_BIT(NI_ADDRCONF_UPDATE_DNS)		|
 		NI_BIT(NI_ADDRCONF_UPDATE_NTP)		|
@@ -1815,21 +1827,32 @@ ni_config_addrconf_update_dhcp4(void)
 static unsigned int
 ni_config_addrconf_update_mask_dhcp6(void)
 {
-	return	ni_config_addrconf_update_dhcp6()	|
-		NI_BIT(NI_ADDRCONF_UPDATE_HOSTNAME)	|
+	/*
+	 * All supported update flags for dhcp6 leases
+	 *
+	 * Note:
+	 * - DHCPv6 does not handle routes --> IPv6 RA's job
+	 */
+	return	NI_BIT(NI_ADDRCONF_UPDATE_HOSTNAME)	|
+		NI_BIT(NI_ADDRCONF_UPDATE_DNS)		|
+		NI_BIT(NI_ADDRCONF_UPDATE_NTP)		|
 		NI_BIT(NI_ADDRCONF_UPDATE_NIS)		|
-		NI_BIT(NI_ADDRCONF_UPDATE_SIP);
+		NI_BIT(NI_ADDRCONF_UPDATE_SIP)		|
+		NI_BIT(NI_ADDRCONF_UPDATE_TZ)		|
+		NI_BIT(NI_ADDRCONF_UPDATE_BOOT);
 }
 
 static unsigned int
 ni_config_addrconf_update_dhcp6(void)
 {
-	/* Note:
-	 * - DHCPv6 does not handle routes --> IPv6 RA's job
-	 * - ypbind does not support ipv6 (DHCPv6 can it).
+	/*
+	 * Update flags enabled for dhcp6 leases by default
 	 */
 	return	NI_BIT(NI_ADDRCONF_UPDATE_DNS)		|
 		NI_BIT(NI_ADDRCONF_UPDATE_NTP)		|
+#ifdef NI_DHCP6_NIS
+		NI_BIT(NI_ADDRCONF_UPDATE_NIS)		|
+#endif
 		NI_BIT(NI_ADDRCONF_UPDATE_TZ)		|
 		NI_BIT(NI_ADDRCONF_UPDATE_BOOT);
 }
@@ -1837,24 +1860,38 @@ ni_config_addrconf_update_dhcp6(void)
 static unsigned int
 ni_config_addrconf_update_mask_auto4(void)
 {
-	return __NI_ADDRCONF_UPDATE_NONE;		/* IP address only */
+	/*
+	 * All supported update flags for auto4 leases
+	 *
+	 * Note: empty mask, supports IP address only
+	 */
+	return __NI_ADDRCONF_UPDATE_NONE;
 }
 
 static unsigned int
 ni_config_addrconf_update_auto4(void)
 {
+	/*
+	 * Update flags enabled for auto4 leases by default
+	 */
 	return ni_config_addrconf_update_mask_auto4();
 }
 
 static unsigned int
 ni_config_addrconf_update_mask_auto6(void)
 {
+	/*
+	 * All supported update flags for auto6 leases
+	 */
 	return NI_BIT(NI_ADDRCONF_UPDATE_DNS);
 }
 
 static unsigned int
 ni_config_addrconf_update_auto6(void)
 {
+	/*
+	 * Update flags enabled for auto6 leases by default
+	 */
 	return ni_config_addrconf_update_mask_auto6();
 }
 
diff --git a/wicked.spec.in b/wicked.spec.in
index 9e903c70..b5dd2add 100644
--- a/wicked.spec.in
+++ b/wicked.spec.in
@@ -52,6 +52,11 @@ Obsoletes:      libwicked-0-6 < %{version}
 %else
 %bcond_with     rfc4361_cid
 %endif
+%if 0%{?suse_version} >= 1500
+%bcond_without  dhcp6_nis
+%else
+%bcond_with     dhcp6_nis
+%endif
 %if 0%{?suse_version} >= 1230
 %bcond_without  systemd
 %bcond_with     dbusstart
@@ -182,6 +187,9 @@ export CFLAGS="-std=gnu89 $RPM_OPT_FLAGS"
 	--with-storedir=%{wicked_storedir}\
 	--with-compat=suse		\
 	--with-fillup-templatesdir=%{_fillupdir}\
+%if %{without dhcp6_nis}
+	--disable-dhcp6-nis		\
+%endif
 %if %{without rfc4361_cid}
 	--disable-dhcp4-rfc4361-cid	\
 %endif
-- 
2.26.2


From 86bcdd9e21bee58807b5813c288e684d2c8eb6ca Mon Sep 17 00:00:00 2001
From: Marius Tomaschewski <mt@suse.de>
Date: Wed, 31 Mar 2021 15:24:33 +0200
Subject: [PATCH 2/6] config: fix to init update flag mask to defaults


diff --git a/client/suse/compat-suse.c b/client/suse/compat-suse.c
index 1e45bd4a..c8d9f8e0 100644
--- a/client/suse/compat-suse.c
+++ b/client/suse/compat-suse.c
@@ -5210,6 +5210,7 @@ __ni_suse_addrconf_dhcp4_options(const ni_sysconfig_t *sc, ni_compat_netdev_t *c
 	}
 
 	if ((string = ni_sysconfig_get_value(sc, "DHCLIENT_UPDATE")) != NULL) {
+		uint = compat->dhcp4.update;
 		if (ni_addrconf_update_flags_parse(&uint, string, " \t,")) {
 			uint &= ni_config_addrconf_update_mask(NI_ADDRCONF_DHCP, AF_INET);
 			compat->dhcp4.update = uint;
@@ -5349,6 +5350,7 @@ __ni_suse_addrconf_dhcp6_options(const ni_sysconfig_t *sc, ni_compat_netdev_t *c
 	ni_bool_t bvalue;
 
 	if ((string = ni_sysconfig_get_value(sc, "DHCLIENT6_UPDATE")) != NULL) {
+		uint = compat->dhcp6.update;
 		if (ni_addrconf_update_flags_parse(&uint, string, " \t,")) {
 			uint &= ni_config_addrconf_update_mask(NI_ADDRCONF_DHCP, AF_INET6);
 			compat->dhcp6.update = uint;
@@ -5625,8 +5627,7 @@ __ni_suse_addrconf_auto6(const ni_sysconfig_t *sc, ni_compat_netdev_t *compat)
 					&compat->auto6.defer_timeout);
 
 		if ((value = ni_sysconfig_get_value(merged, "AUTO6_UPDATE"))) {
-			unsigned int temp;
-
+			unsigned int temp = compat->auto6.update;
 			if (ni_addrconf_update_flags_parse(&temp, value, " \t,")) {
 				temp &= ni_config_addrconf_update_mask(NI_ADDRCONF_AUTOCONF, AF_INET6);
 				compat->auto6.update = temp;
diff --git a/src/config.c b/src/config.c
index 641c0768..4b0afb82 100644
--- a/src/config.c
+++ b/src/config.c
@@ -1262,6 +1262,8 @@ ni_config_parse_update_targets(unsigned int *update_mask, const xml_node_t *node
 	} else {
 		ni_string_split(&targets, node->cdata, " \t,|", 0);
 	}
+
+	mask = *update_mask;
 	if (ni_addrconf_update_flags_parse_names(&mask, &targets))
 		*update_mask = mask;
 	ni_string_array_destroy(&targets);
-- 
2.26.2


From 840a9372a69c9d8f6c29af2dd152b93233739418 Mon Sep 17 00:00:00 2001
From: Marius Tomaschewski <mt@suse.de>
Date: Wed, 31 Mar 2021 15:29:05 +0200
Subject: [PATCH 3/6] utils: add an string array find match utility


diff --git a/include/wicked/util.h b/include/wicked/util.h
index 76e61af4..686a0c07 100644
--- a/include/wicked/util.h
+++ b/include/wicked/util.h
@@ -116,6 +116,8 @@ extern int		ni_string_array_set(ni_string_array_t *, unsigned int, const char *)
 extern int		ni_string_array_get(ni_string_array_t *, unsigned int, char **);
 extern const char *	ni_string_array_at(ni_string_array_t *, unsigned int);
 extern int		ni_string_array_index(const ni_string_array_t *, const char *);
+extern unsigned int	ni_string_array_find(const ni_string_array_t *, unsigned int, const char *,
+					ni_bool_t (*)(const char *, const char *), const char **);
 extern int		ni_string_array_remove_index(ni_string_array_t *, unsigned int);
 extern int		ni_string_array_remove_match(ni_string_array_t *, const char *, unsigned int);
 extern void		ni_string_array_comm(const ni_string_array_t *a, const ni_string_array_t *b,
diff --git a/src/util.c b/src/util.c
index a8079e97..235f4413 100644
--- a/src/util.c
+++ b/src/util.c
@@ -188,6 +188,23 @@ ni_string_array_index(const ni_string_array_t *nsa, const char *str)
 	return -1;
 }
 
+unsigned int
+ni_string_array_find(const ni_string_array_t *nsa, unsigned int pos, const char *item,
+		ni_bool_t (*match)(const char *a, const char *b), const char **ret)
+{
+	if (!nsa || !match)
+		return -1U;
+
+	for (; pos < nsa->count; ++pos) {
+		if (match(nsa->data[pos], item)) {
+			if (ret)
+				*ret = item;
+			return pos;
+		}
+	}
+	return -1U;
+}
+
 /*
  * Remove string at index @pos
  */
-- 
2.26.2


From 7ae954e38d366e40913716eb6595255390931d1b Mon Sep 17 00:00:00 2001
From: Marius Tomaschewski <mt@suse.de>
Date: Wed, 31 Mar 2021 15:32:03 +0200
Subject: [PATCH 4/6] nis: cleanup nis definitions for wicked


diff --git a/include/wicked/nis.h b/include/wicked/nis.h
index 3c6ca93d..186026f3 100644
--- a/include/wicked/nis.h
+++ b/include/wicked/nis.h
@@ -1,25 +1,43 @@
 /*
- * NIS definitions for wicked
+ *	NIS definitions for wicked
  *
- * Copyright (C) 2010-2012 Olaf Kirch <okir@suse.de>
+ *	Copyright (C) 2010-2012 Olaf Kirch <okir@suse.de>
+ *	Copyright (C) 2010-2021 SUSE LCC
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	This program is distributed in the hope that it will be useful,
+ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *	GNU General Public License for more details.
+ *
+ *	You should have received a copy of the GNU General Public License
+ *	along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *	Authors:
+ *		Olaf Kirch
+ *		Marius Tomaschewski
  */
 
-#ifndef __WICKED_NIS_H__
-#define __WICKED_NIS_H__
+#ifndef NI_WICKED_NIS_H
+#define NI_WICKED_NIS_H
 
 #include <wicked/util.h>
 
-#define _PATH_YP_CONF		"/etc/yp.conf"
+#define NI_PATH_YP_CONF		"/etc/yp.conf"
 
-typedef enum nis_nis_binding {
+typedef enum ni_nis_binding {
 	NI_NISCONF_STATIC,
 	NI_NISCONF_BROADCAST,
 	NI_NISCONF_SLP,
-} nis_nis_binding_t;
+} ni_nis_binding_t;
 
 typedef struct ni_nis_domain {
 	char *			domainname;
-	nis_nis_binding_t	binding;		/* static, broadcast, slp */
+	ni_nis_binding_t	binding;		/* static, broadcast, slp */
 	ni_string_array_t	servers;
 } ni_nis_domain_t;
 
@@ -30,7 +48,7 @@ typedef struct ni_nis_domain_array {
 
 struct ni_nis_info {
 	char *			domainname;
-	nis_nis_binding_t	default_binding;	/* static, broadcast, slp */
+	ni_nis_binding_t	default_binding;	/* static, broadcast, slp */
 	ni_string_array_t	default_servers;
 
 	ni_nis_domain_array_t	domains;
@@ -40,10 +58,10 @@ extern ni_nis_info_t *		ni_nis_info_new(void);
 extern void			ni_nis_info_free(ni_nis_info_t *);
 extern ni_nis_domain_t *	ni_nis_domain_find(const ni_nis_info_t *, const char *);
 extern ni_nis_domain_t *	ni_nis_domain_new(ni_nis_info_t *, const char *);
-extern nis_nis_binding_t	ni_nis_binding_name_to_type(const char *);
-extern const char *		ni_nis_binding_type_to_name(nis_nis_binding_t);
+extern ni_nis_binding_t		ni_nis_binding_name_to_type(const char *);
+extern const char *		ni_nis_binding_type_to_name(ni_nis_binding_t);
 
 extern ni_nis_info_t *		ni_nis_parse_yp_conf(const char *);
 extern int			ni_nis_write_yp_conf(const char *, const ni_nis_info_t *, const char *);
 
-#endif /* __WICKED_NIS_H__ */
+#endif /* NI_WICKED_NIS_H */
diff --git a/src/nis.c b/src/nis.c
index 6ed6c3a9..398b8dce 100644
--- a/src/nis.c
+++ b/src/nis.c
@@ -1,7 +1,26 @@
 /*
- * NIS definitions for wicked
+ *	NIS definitions for wicked
+ *
+ *	Copyright (C) 2010-2012 Olaf Kirch <okir@suse.de>
+ *	Copyright (C) 2010-2021 SUSE LCC
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	This program is distributed in the hope that it will be useful,
+ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *	GNU General Public License for more details.
+ *
+ *	You should have received a copy of the GNU General Public License
+ *	along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *	Authors:
+ *		Olaf Kirch
+ *		Marius Tomaschewski
  *
- * Copyright (C) 2010-2012 Olaf Kirch <okir@suse.de>
  */
 #ifdef HAVE_CONFIG_H
 #include "config.h"
@@ -130,6 +149,7 @@ void
 ni_nis_info_free(ni_nis_info_t *nis)
 {
 	ni_string_free(&nis->domainname);
+	ni_string_array_destroy(&nis->default_servers);
 	ni_nis_domain_array_destroy(&nis->domains);
 }
 
@@ -154,10 +174,12 @@ ni_nis_domain_new(ni_nis_info_t *nis, const char *domainname)
 	ni_nis_domain_t *dom;
 
 	dom = calloc(1, sizeof(*dom));
-	ni_string_dup(&dom->domainname, domainname);
-	dom->binding = NI_NISCONF_STATIC;
+	if (dom) {
+		ni_string_dup(&dom->domainname, domainname);
+		dom->binding = NI_NISCONF_STATIC;
 
-	ni_nis_domain_array_append(&nis->domains, dom);
+		ni_nis_domain_array_append(&nis->domains, dom);
+	}
 	return dom;
 }
 
@@ -197,7 +219,7 @@ static ni_intmap_t	__nis_bindings[] = {
 	{ NULL }
 };
 
-nis_nis_binding_t
+ni_nis_binding_t
 ni_nis_binding_name_to_type(const char *name)
 {
 	unsigned int value;
@@ -208,7 +230,7 @@ ni_nis_binding_name_to_type(const char *name)
 }
 
 const char *
-ni_nis_binding_type_to_name(nis_nis_binding_t mode)
+ni_nis_binding_type_to_name(ni_nis_binding_t mode)
 {
 	return ni_format_uint_mapped(mode, __nis_bindings);
 }
diff --git a/src/state.c b/src/state.c
index dac6e333..53dbefa5 100644
--- a/src/state.c
+++ b/src/state.c
@@ -53,7 +53,7 @@ __ni_system_nis_get(void)
 	char domainname[256];
 	ni_nis_info_t *nis;
 
-	if ((nis = ni_nis_parse_yp_conf(_PATH_YP_CONF)) == NULL)
+	if ((nis = ni_nis_parse_yp_conf(NI_PATH_YP_CONF)) == NULL)
 		return NULL;
 
 	if (nis->domainname == NULL
@@ -66,14 +66,14 @@ __ni_system_nis_get(void)
 int
 __ni_system_nis_put(const ni_nis_info_t *nis)
 {
-	const char *tempfile = _PATH_YP_CONF ".new";
+	const char *tempfile = NI_PATH_YP_CONF ".new";
 
 	if (ni_nis_write_yp_conf(tempfile, nis, NULL) < 0) {
 		unlink(tempfile);
 		return -1;
 	}
-	if (rename(tempfile, _PATH_YP_CONF) < 0) {
-		ni_error("cannot move temp file to %s: %m", _PATH_YP_CONF);
+	if (rename(tempfile, NI_PATH_YP_CONF) < 0) {
+		ni_error("cannot move temp file to %s: %m", NI_PATH_YP_CONF);
 		unlink(tempfile);
 		return -1;
 	}
@@ -89,14 +89,14 @@ __ni_system_nis_put(const ni_nis_info_t *nis)
 int
 __ni_system_nis_backup(void)
 {
-	return ni_backup_file_to(_PATH_YP_CONF, ni_config_backupdir());
+	return ni_backup_file_to(NI_PATH_YP_CONF, ni_config_backupdir());
 }
 
 int
 __ni_system_nis_restore(void)
 {
 	__ni_system_nis_domain_put(NULL);
-	return ni_restore_file_from(_PATH_YP_CONF, ni_config_backupdir());
+	return ni_restore_file_from(NI_PATH_YP_CONF, ni_config_backupdir());
 }
 
 ni_resolver_info_t *
-- 
2.26.2


From e23949fe561cd16b52ab488f92138b5184e9cb5e Mon Sep 17 00:00:00 2001
From: Marius Tomaschewski <mt@suse.de>
Date: Wed, 31 Mar 2021 15:44:53 +0200
Subject: [PATCH 5/6] lease: consider nis with multiple domains for dhcp6


diff --git a/schema/addrconf.xml b/schema/addrconf.xml
index 64a68cfe..2ed31266 100644
--- a/schema/addrconf.xml
+++ b/schema/addrconf.xml
@@ -8,6 +8,12 @@
      Generic Addrconf facilities
      ================================================= -->
 <service name="addrconf" interface="org.opensuse.Network.Addrconf" object-class="addrconf-device">
+  <define name="nis-domain" class="dict">
+      <domainname type="string" />
+      <binding type="uint32" />
+      <servers class="array" element-type="string" element-name="server" />
+  </define>
+
   <define name="lease-type" class="dict">
     <description>
       This type describes an address configuration obtained by one of
@@ -33,14 +39,12 @@
 
     <resolver class="dict">
       <default-domain type="string" />
-      <servers class="array" element-type="string" />
-      <search class="array" element-type="string" />
+      <search class="array" element-type="string" element-name="domain" />
+      <servers class="array" element-type="string" element-name="server" />
     </resolver>
 
-    <nis class="dict">
-      <domainname type="string" />
-      <binding type="uint32" />
-      <servers class="array" element-type="string" />
+    <nis class="dict" extends="nis-domain">
+      <domains class="array" element-type="nis-domain" element-name="domain" />
     </nis>
 
     <log-servers class="array" element-type="string" />
diff --git a/src/dbus-objects/misc.c b/src/dbus-objects/misc.c
index 454b4740..673c2903 100644
--- a/src/dbus-objects/misc.c
+++ b/src/dbus-objects/misc.c
@@ -1816,6 +1816,40 @@ __ni_objectmodel_get_addrconf_dhcp6_dict(const struct ni_addrconf_lease_dhcp6 *d
 	__ni_objectmodel_get_addrconf_dhcp_opts_dict(dhcp6->options, dict, 0, 65535);
 }
 
+static dbus_bool_t
+__ni_objectmodel_get_nis_info(const ni_nis_info_t *nis, ni_dbus_variant_t *dict, DBusError *error)
+{
+	ni_dbus_variant_t *domains;
+	const ni_nis_domain_t *dom;
+	unsigned int i;
+
+	ni_dbus_variant_init_dict(dict);
+
+	if (nis->domainname || nis->default_servers.count) {
+		ni_dbus_dict_add_string(dict, "domainname", nis->domainname);
+		ni_dbus_dict_add_uint32(dict, "binding", nis->default_binding);
+		__ni_objectmodel_set_string_array(dict, "servers", &nis->default_servers);
+	}
+
+	if (nis->domains.count && (domains = ni_dbus_dict_add(dict, "domains"))) {
+
+		ni_dbus_dict_array_init(domains);
+		for (i = 0; i < nis->domains.count; ++i) {
+			if (!(dom = nis->domains.data[i]))
+				continue;
+
+			if (!(dict = ni_dbus_dict_array_add(domains)))
+				continue;
+
+			ni_dbus_variant_init_dict(dict);
+			ni_dbus_dict_add_string(dict, "domainname", dom->domainname);
+			ni_dbus_dict_add_uint32(dict, "binding", dom->binding);
+			__ni_objectmodel_set_string_array(dict, "servers", &dom->servers);
+		}
+	}
+	return TRUE;
+}
+
 dbus_bool_t
 __ni_objectmodel_get_addrconf_lease(const ni_addrconf_lease_t *lease,
 						ni_dbus_variant_t *result,
@@ -1866,17 +1900,8 @@ __ni_objectmodel_get_addrconf_lease(const ni_addrconf_lease_t *lease,
 		__ni_objectmodel_set_string_array(child, "search", &resolv->dns_search);
 	}
 
-	if (lease->nis) {
-		ni_nis_info_t *nis = lease->nis;
-
-		child = ni_dbus_dict_add(result, "nis");
-		ni_dbus_variant_init_dict(child);
-
-		if (nis->domainname)
-			ni_dbus_dict_add_string(child, "domainname", nis->domainname);
-		ni_dbus_dict_add_uint32(child, "binding", nis->default_binding);
-		__ni_objectmodel_set_string_array(child, "servers", &nis->default_servers);
-	}
+	if (lease->nis && (child = ni_dbus_dict_add(result, "nis")))
+		__ni_objectmodel_get_nis_info(lease->nis, child, error);
 
 	__ni_objectmodel_set_string_array(result, "log-servers", &lease->log_servers);
 	__ni_objectmodel_set_string_array(result, "ntp-servers", &lease->ntp_servers);
@@ -2201,6 +2226,65 @@ __ni_objectmodel_set_addrconf_dhcp6_data(struct ni_addrconf_lease_dhcp6 *dhcp6,
 	return TRUE;
 }
 
+static dbus_bool_t
+__ni_objectmodel_set_nis_info(ni_nis_info_t **result, const ni_dbus_variant_t *dict, DBusError *error)
+{
+	const ni_dbus_variant_t *servers, *domains;
+	const char *string_value;
+	uint32_t value32;
+	ni_nis_info_t *nis;
+
+	if (!result || !dict || !ni_dbus_variant_is_dict(dict))
+		return FALSE;
+
+	*result = NULL;
+	if (!(nis = ni_nis_info_new()))
+		return FALSE;
+
+	if (__ni_objectmodel_get_domain_string(dict, "domainname", &string_value))
+		ni_string_dup(&nis->domainname, string_value);
+
+	if (ni_dbus_dict_get_uint32(dict, "binding", &value32))
+		nis->default_binding = value32;
+
+	servers = ni_dbus_dict_get(dict, "servers");
+	if (servers && !__ni_objectmodel_get_address_array(&nis->default_servers,
+			servers, error, "nis servers")) {
+		ni_nis_info_free(nis);
+		return FALSE;
+	}
+
+	domains = ni_dbus_dict_get(dict, "domains");
+	if (domains && ni_dbus_variant_is_dict_array(domains)) {
+		unsigned int i;
+
+		for (i = 0; i < domains->array.len; ++i) {
+			ni_nis_domain_t *dom;
+
+			dict = &domains->variant_array_value[i];
+			if (!ni_dbus_variant_is_dict(dict) ||
+			    !__ni_objectmodel_get_domain_string(dict, "domainname", &string_value))
+				continue;
+
+			if (ni_nis_domain_find(nis, string_value))
+				continue;
+
+			if ((dom = ni_nis_domain_new(nis, string_value))) {
+				if (ni_dbus_dict_get_uint32(dict, "binding", &value32))
+					dom->binding = value32;
+
+				if ((servers = ni_dbus_dict_get(dict, "servers"))) {
+					__ni_objectmodel_get_address_array(&dom->servers, servers,
+									error, "nis-domain servers");
+				}
+			}
+		}
+	}
+
+	*result = nis;
+	return TRUE;
+}
+
 dbus_bool_t
 __ni_objectmodel_set_addrconf_lease(ni_addrconf_lease_t *lease,
 						const ni_dbus_variant_t *argument,
@@ -2245,23 +2329,9 @@ __ni_objectmodel_set_addrconf_lease(ni_addrconf_lease_t *lease,
 	if (!__ni_objectmodel_set_resolver_dict(&lease->resolver, argument, error))
 		return FALSE;
 
-	if ((child = ni_dbus_dict_get(argument, "nis")) != NULL) {
-		ni_nis_info_t *nis = ni_nis_info_new();
-		ni_dbus_variant_t *list;
-
-		lease->nis = nis;
-		if (__ni_objectmodel_get_domain_string(child, "domainname",
-								&string_value))
-			ni_string_dup(&nis->domainname, string_value);
-
-		if (ni_dbus_dict_get_uint32(child, "binding", &value32))
-			nis->default_binding = value32;
-
-		if ((list = ni_dbus_dict_get(child, "servers")) != NULL
-		 && !__ni_objectmodel_get_address_array(&nis->default_servers, list,
-							error, "servers"))
-			return FALSE;
-	}
+	if ((child = ni_dbus_dict_get(argument, "nis"))
+	 && !__ni_objectmodel_set_nis_info(&lease->nis, child, error))
+		return FALSE;
 
 	if ((child = ni_dbus_dict_get(argument, "log-servers")) != NULL
 	 && !__ni_objectmodel_get_address_array(&lease->log_servers, child, error,
diff --git a/src/dhcp6/lease.c b/src/dhcp6/lease.c
index a9c03d27..f4964473 100644
--- a/src/dhcp6/lease.c
+++ b/src/dhcp6/lease.c
@@ -240,6 +240,7 @@ ni_dhcp6_lease_data_to_xml(const ni_addrconf_lease_t *lease, xml_node_t *node, c
 	} *g, group_map[] = {
 		{ NI_ADDRCONF_LEASE_XML_DNS_DATA_NODE, ni_addrconf_lease_dns_data_to_xml },
 		{ NI_ADDRCONF_LEASE_XML_NTP_DATA_NODE, ni_addrconf_lease_ntp_data_to_xml },
+		{ NI_ADDRCONF_LEASE_XML_NIS_DATA_NODE, ni_addrconf_lease_nis_data_to_xml },
 		{ NI_ADDRCONF_LEASE_XML_SIP_DATA_NODE, ni_addrconf_lease_sip_data_to_xml },
 		{ NI_ADDRCONF_LEASE_XML_PTZ_DATA_NODE, ni_addrconf_lease_ptz_data_to_xml },
 		{ NI_ADDRCONF_LEASE_XML_OPTS_DATA_NODE, ni_addrconf_lease_opts_data_to_xml },
@@ -546,6 +547,10 @@ ni_dhcp6_lease_data_from_xml(ni_addrconf_lease_t *lease, const xml_node_t *node,
 			if (ni_addrconf_lease_ntp_data_from_xml(lease, child, ifname) < 0)
 				return -1;
 		} else
+		if (ni_string_eq(child->name, NI_ADDRCONF_LEASE_XML_NIS_DATA_NODE)) {
+			if (ni_addrconf_lease_nis_data_from_xml(lease, child, ifname) < 0)
+				return -1;
+		} else
 		if (ni_string_eq(child->name, NI_ADDRCONF_LEASE_XML_SIP_DATA_NODE)) {
 			if (ni_addrconf_lease_sip_data_from_xml(lease, child, ifname) < 0)
 				return -1;
diff --git a/src/leasefile.c b/src/leasefile.c
index 5a39ca4f..addef72d 100644
--- a/src/leasefile.c
+++ b/src/leasefile.c
@@ -256,6 +256,7 @@ ni_addrconf_lease_nis_data_to_xml(const ni_addrconf_lease_t *lease, xml_node_t *
 	unsigned int i, j;
 	ni_nis_info_t *nis;
 	xml_node_t *data;
+	const char *name;
 
 	(void)ifname;
 
@@ -266,46 +267,53 @@ ni_addrconf_lease_nis_data_to_xml(const ni_addrconf_lease_t *lease, xml_node_t *
 	/* Default domain */
 	data = xml_node_new("default", NULL);
 	if (!ni_string_empty(nis->domainname)) {
-		count++;
-		xml_node_new_element("domain", data, nis->domainname);
-	}
-	if (nis->default_binding == NI_NISCONF_BROADCAST ||
-	    nis->default_binding == NI_NISCONF_STATIC) {
-		/* no SLP here */
-		count++;
-		xml_node_new_element("binding", data,
-			ni_nis_binding_type_to_name(nis->default_binding));
-	}
-	/* Only in when static binding? */
-	for (i = 0; i < nis->default_servers.count; ++i) {
-		const char *server = nis->default_servers.data[i];
-		if (ni_string_empty(server))
-			continue;
-		count++;
-		xml_node_new_element("server", data, server);
+		if (xml_node_new_element("domain", data, nis->domainname))
+			count++;
+
+		if (nis->default_binding == NI_NISCONF_BROADCAST ||
+		    nis->default_binding == NI_NISCONF_STATIC) {
+			/* no SLP here */
+			name = ni_nis_binding_type_to_name(nis->default_binding);
+			if (name && xml_node_new_element("binding", data, name))
+				count++;
+		}
+		/* Only in when static binding? */
+		for (i = 0; i < nis->default_servers.count; ++i) {
+			const char *server = nis->default_servers.data[i];
+			if (ni_string_empty(server))
+				continue;
+			if (xml_node_new_element("server", data, server))
+				count++;
+		}
 	}
 	if (count) {
 		xml_node_add_child(node, data);
+	} else {
+		xml_node_free(data);
 	}
 
-	/* Further domains */
+	/* Further domains with servers */
 	for (i = 0; i < nis->domains.count; ++i) {
 		ni_nis_domain_t *dom = nis->domains.data[i];
 		if (!dom || ni_string_empty(dom->domainname))
 			continue;
 
-		count++;
-		data = xml_node_new("domain", node);
-		xml_node_new_element("domain", data, dom->domainname);
-		if (ni_nis_binding_type_to_name(nis->default_binding)) {
-			xml_node_new_element("binding", data,
-				ni_nis_binding_type_to_name(nis->default_binding));
-		}
+		if (!(data = xml_node_new("domain", node)))
+			continue;
+
+		if (xml_node_new_element("domain", data, dom->domainname))
+			count++;
+
+		name = ni_nis_binding_type_to_name(dom->binding);
+		if (name && xml_node_new_element("binding", data, name))
+			count++;
+
 		for (j = 0; j < dom->servers.count; ++j) {
 			const char *server = dom->servers.data[j];
 			if (ni_string_empty(server))
 				continue;
-			xml_node_new_element("server", data, server);
+			if (xml_node_new_element("server", data, server))
+				count++;
 		}
 	}
 
diff --git a/src/leaseinfo.c b/src/leaseinfo.c
index d0fc00f3..aecae13e 100644
--- a/src/leaseinfo.c
+++ b/src/leaseinfo.c
@@ -58,7 +58,7 @@ static void		__ni_leaseinfo_print_string(FILE *, const char *,
 					const char *, unsigned int);
 static void		__ni_leaseinfo_print_string_array(FILE *, const char *,
 					const char *, const ni_string_array_t *,
-					const char *);
+					const char *, unsigned int);
 static void		__ni_leaseinfo_dhcp4_dump(FILE *,
 				const ni_addrconf_lease_t *,
 				const char *, const char *);
@@ -118,11 +118,11 @@ __ni_leaseinfo_print_string(FILE *out, const char *prefix, const char *name,
 
 static void
 __ni_leaseinfo_print_string_array(FILE *out, const char *prefix, const char *name,
-				const ni_string_array_t *str_arr, const char *sep)
+				const ni_string_array_t *str_arr, const char *sep,
+				unsigned int index)
 {
 	char *key = NULL;
 	unsigned int i;
-	ni_bool_t doneone;
 
 	if (!str_arr || str_arr->count == 0)
 		return;
@@ -130,15 +130,11 @@ __ni_leaseinfo_print_string_array(FILE *out, const char *prefix, const char *nam
 	if (!sep)
 		sep = " ";
 
-	doneone = FALSE;
 	fprintf(out, "%s='", __ni_keyword_format
-		(&key, prefix, name, 0));
+		(&key, prefix, name, index));
 
 	for (i = 0; i < str_arr->count; ++i) {
-		if (doneone)
-			fprintf(out, " ");
-		fprintf(out, "%s", str_arr->data[i]);
-		doneone = TRUE;
+		fprintf(out, "%s%s", i ? sep : "", str_arr->data[i]);
 	}
 	fprintf(out, "'\n");
 
@@ -286,9 +282,9 @@ __ni_leaseinfo_print_routes(FILE *out, const char *prefix,
 	}
 
 	__ni_leaseinfo_print_string_array(out, prefix, "ROUTES",
-					&routes_entry_arr, " ");
+					&routes_entry_arr, " ", 0);
 	__ni_leaseinfo_print_string_array(out, prefix, "GATEWAYS",
-					&gw_entry_arr, " ");
+					&gw_entry_arr, " ", 0);
 
 	ni_string_array_destroy(&routes_entry_arr);
 	ni_string_array_destroy(&gw_entry_arr);
@@ -343,25 +339,29 @@ __ni_leaseinfo_print_prefixes(FILE *out, const char *prefix, ni_dhcp6_ia_t *ia_l
 static void
 __ni_leaseinfo_print_nis(FILE *out, const char *prefix, ni_nis_info_t *nis)
 {
-	unsigned int i;
+	unsigned int i, index = 0;
 
 	if (!nis)
 		return;
 
-	__ni_leaseinfo_print_string(out, prefix, "NISDOMAIN", nis->domainname,
-				NULL, 0);
+	if (!ni_string_empty(nis->domainname) || nis->default_servers.count) {
+		__ni_leaseinfo_print_string(out, prefix, "NISDOMAIN", nis->domainname,
+				NULL, index);
 
-	__ni_leaseinfo_print_string_array(out, prefix, "NISSERVERS",
-					&nis->default_servers, " ");
+		__ni_leaseinfo_print_string_array(out, prefix, "NISSERVERS",
+						&nis->default_servers, " ", index);
+		index++;
+	}
 
 	for (i = 0; i < nis->domains.count; ++i) {
 		__ni_leaseinfo_print_string(out, prefix, "NISDOMAIN",
 					nis->domains.data[i]->domainname,
-					NULL, i);
+					NULL, index);
 
 		__ni_leaseinfo_print_string_array(out, prefix, "NISSERVERS",
 						&nis->domains.data[i]->servers,
-						" ");
+						" ", index);
+		index++;
 	}
 }
 
@@ -409,11 +409,11 @@ __ni_leaseinfo_print_resolver(FILE *out, const char *prefix,
 
 	__ni_leaseinfo_qualify_addrs(&dns_servers, &resolver->dns_servers, ifname);
 	__ni_leaseinfo_print_string_array(out, prefix, "DNSSERVERS",
-					&dns_servers, " ");
+					&dns_servers, " ", 0);
 	ni_string_array_destroy(&dns_servers);
 
 	__ni_leaseinfo_print_string_array(out, prefix, "DNSSEARCH",
-					&resolver->dns_search, " ");
+					&resolver->dns_search, " ", 0);
 }
 
 static void
@@ -422,11 +422,11 @@ __ni_leaseinfo_print_netbios(FILE *out, const char *prefix,
 {
 	/* Netbios Name Servers */
 	__ni_leaseinfo_print_string_array(out, prefix, "NETBIOSNAMESERVER",
-					&lease->netbios_name_servers, " ");
+					&lease->netbios_name_servers, " ", 0);
 
 	/* Netbios Datagram Distribution Servers */
 	__ni_leaseinfo_print_string_array(out, prefix, "NETBIOSDDSERVER",
-					&lease->netbios_dd_servers, " ");
+					&lease->netbios_dd_servers, " ", 0);
 
 	/* Netbios Scope */
 	__ni_leaseinfo_print_string(out, prefix, "NETBIOSSCOPE",
@@ -717,24 +717,23 @@ __ni_leaseinfo_dump(FILE *out, const ni_addrconf_lease_t *lease,
 	if (lease->family == AF_INET6)
 		__ni_leaseinfo_print_prefixes(out, prefix, lease->dhcp6.ia_list);
 
-	/* Only applicable for ipv4. */
-	if (lease->family == AF_INET)
-		__ni_leaseinfo_print_nis(out, prefix, lease->nis);
+	/* NIS domains and servers */
+	__ni_leaseinfo_print_nis(out, prefix, lease->nis);
 
 	/* DNS Servers and Domains */
 	__ni_leaseinfo_print_resolver(out, prefix, lease->resolver, ifname);
 
 	/* NTP Servers */
 	__ni_leaseinfo_print_string_array(out, prefix, "NTPSERVERS",
-					&lease->ntp_servers, " ");
+					&lease->ntp_servers, " ", 0);
 
 	/* NDS Servers */
 	__ni_leaseinfo_print_string_array(out, prefix, "NDSSERVERS",
-					&lease->nds_servers, " ");
+					&lease->nds_servers, " ", 0);
 
 	/* NDS Context */
 	__ni_leaseinfo_print_string_array(out, prefix, "NDSCONTEXT",
-					&lease->nds_context, " ");
+					&lease->nds_context, " ", 0);
 
 	/* NDS Tree */
 	__ni_leaseinfo_print_string(out, prefix, "NDSTREE", lease->nds_tree,
-- 
2.26.2


From fe395ee115d4a8150b1954f7bdba8f4df1e74641 Mon Sep 17 00:00:00 2001
From: Marius Tomaschewski <mt@suse.de>
Date: Wed, 31 Mar 2021 15:58:11 +0200
Subject: [PATCH 6/6] dhcp6: set nis servers from response msg in lease


diff --git a/src/dhcp6/protocol.c b/src/dhcp6/protocol.c
index 7a0a6b7c..eb6d8a53 100644
--- a/src/dhcp6/protocol.c
+++ b/src/dhcp6/protocol.c
@@ -41,9 +41,8 @@
 #include <wicked/addrconf.h>
 #include <wicked/resolver.h>
 #include <wicked/ipv6.h>
-#if 0
-#include <wicked/route.h>
 #include <wicked/nis.h>
+#if 0
 #include <wicked/xml.h>
 #endif
 
@@ -1381,8 +1380,6 @@ __ni_dhcp6_build_oro_opts(ni_dhcp6_device_t *dev,
 	if (dev->config->update & NI_BIT(NI_ADDRCONF_UPDATE_NIS)) {
 		ni_dhcp6_option_request_append(oro, NI_DHCP6_OPTION_NIS_SERVERS);
 		ni_dhcp6_option_request_append(oro, NI_DHCP6_OPTION_NIS_DOMAIN_NAME);
-		ni_dhcp6_option_request_append(oro, NI_DHCP6_OPTION_NISP_SERVERS);
-		ni_dhcp6_option_request_append(oro, NI_DHCP6_OPTION_NISP_DOMAIN_NAME);
 	}
 	if (dev->config->update & NI_BIT(NI_ADDRCONF_UPDATE_SIP)) {
 		ni_dhcp6_option_request_append(oro, NI_DHCP6_OPTION_SIP_SERVER_D);
@@ -2720,6 +2717,82 @@ ni_dhcp6_ia_copy_to_lease_addrs(const ni_dhcp6_device_t *dev, ni_addrconf_lease_
 	return count;
 }
 
+static int
+ni_dhcp6_lease_add_nis_servers(ni_string_array_t *dst, const ni_string_array_t *src)
+{
+	const char *server;
+	unsigned int i;
+
+	if (!dst || !src)
+		return -1;
+
+	for (i = 0; i < src->count; ++i) {
+		server = src->data[i];
+
+		/* unique servers only */
+		if (ni_string_array_find(dst, 0, server, ni_string_eq_nocase, NULL) != -1U)
+			continue;
+
+		ni_string_array_append(dst, server);
+	}
+
+	return 0;
+}
+
+static int
+ni_dhcp6_lease_add_nis_domains(ni_nis_info_t *nis, const ni_string_array_t *domains,
+							const ni_string_array_t *servers)
+{
+	ni_nis_domain_t *dom;
+	const char *domain;
+	unsigned int i;
+
+	if (!nis || !domains || !servers)
+		return -1;
+
+	for (i = 0; i < domains->count; ++i) {
+		domain = domains->data[i];
+
+		/* unique domains only */
+		if (ni_nis_domain_find(nis, domain))
+			continue;
+
+		if ((dom = ni_nis_domain_new(nis, domain)))
+			ni_dhcp6_lease_add_nis_servers(&dom->servers, servers);
+	}
+
+	return 0;
+}
+
+int
+ni_dhcp6_lease_set_nis_info(ni_addrconf_lease_t *lease, const ni_string_array_t *domains,
+							const ni_string_array_t *servers)
+{
+	if (!lease || !domains || !servers)
+		return -1;
+
+	if (lease->nis) {
+		ni_nis_info_free(lease->nis);
+		lease->nis = NULL;
+	}
+
+	if (!domains->count && !servers->count)
+		return 0;
+
+	if (!(lease->nis = ni_nis_info_new()))
+		return -1;
+
+	if (domains->count == 1) {
+		ni_string_dup(&lease->nis->domainname, domains->data[0]);
+		ni_dhcp6_lease_add_nis_servers(&lease->nis->default_servers, servers);
+	} else
+	if (domains->count) {
+		ni_dhcp6_lease_add_nis_domains(lease->nis, domains, servers);
+	}
+
+	return 0;
+}
+
 int
 ni_dhcp6_parse_client_options(ni_dhcp6_device_t *dev, ni_dhcp6_message_t *msg, ni_buffer_t *buffer)
 {
@@ -2937,9 +3010,7 @@ ni_dhcp6_parse_client_options(ni_dhcp6_device_t *dev, ni_dhcp6_message_t *msg, n
 				for (i = 0; i < temp.count; ++i) {
 					ni_debug_dhcp("%s: %s", ni_dhcp6_option_name(option),
 							temp.data[i]);
-					/* TODO
 					ni_string_array_append(&nis_servers, temp.data[i]);
-					*/
 				}
 			}
 			ni_string_array_destroy(&temp);
@@ -2949,9 +3020,7 @@ ni_dhcp6_parse_client_options(ni_dhcp6_device_t *dev, ni_dhcp6_message_t *msg, n
 				for (i = 0; i < temp.count; ++i) {
 					ni_debug_dhcp("%s: %s", ni_dhcp6_option_name(option),
 							temp.data[i]);
-					/* TODO:
 					ni_string_array_append(&nis_domains, temp.data[i]);
-					*/
 				}
 			}
 			ni_string_array_destroy(&temp);
@@ -3081,13 +3150,10 @@ ni_dhcp6_parse_client_options(ni_dhcp6_device_t *dev, ni_dhcp6_message_t *msg, n
 		}
 	}
 
-	if (nis_domains.count) {
-		/* TODO */
-	}
-
 	/* FIXME: too early here -- do it after parsing depending on the state? */
 	ni_dhcp6_ia_copy_to_lease_addrs(dev, lease);
 
+	ni_dhcp6_lease_set_nis_info(lease, &nis_domains, &nis_servers);
 	ni_string_array_destroy(&nis_servers);
 	ni_string_array_destroy(&nis_domains);
 	return 0;
-- 
2.26.2

