>From b8740437b7a1e6fbe2f7221e5b4c4b44dba2d4d4 Mon Sep 17 00:00:00 2001
From: Pavel Reichl <preichl@redhat.com>
Date: Wed, 8 Jul 2015 09:08:03 -0400
Subject: [PATCH 2/5] DYNDNS: support mult. interfaces for dyndns_iface opt

Resolves:
https://fedorahosted.org/sssd/ticket/2549
---
 src/man/sssd-ad.5.xml            |  7 ++--
 src/man/sssd-ipa.5.xml           |  7 ++--
 src/providers/dp_dyndns.c        |  6 ++++
 src/providers/dp_dyndns.h        |  4 +++
 src/providers/ldap/sdap_dyndns.c | 72 +++++++++++++++++++++++++++++++++++-----
 5 files changed, 84 insertions(+), 12 deletions(-)

diff --git a/src/man/sssd-ad.5.xml b/src/man/sssd-ad.5.xml
index 938a443e027b9bf83c75c240a7d6b2a0876b92c8..4e2aedb57e3d8e1ce5b674e31c6a3d1fe293d4cb 100644
--- a/src/man/sssd-ad.5.xml
+++ b/src/man/sssd-ad.5.xml
@@ -754,15 +754,18 @@ ad_gpo_map_deny = +my_pam_service
                     <listitem>
                         <para>
                             Optional. Applicable only when dyndns_update
-                            is true. Choose the interface whose IP address
+                            is true. Choose the interfaces whose IP addresses
                             should be used for dynamic DNS updates.
                         </para>
                         <para>
-                            NOTE: This option currently supports only one interface.
+                            NOTE: This option supports multiple interfaces.
                         </para>
                         <para>
                             Default: Use the IP address of the AD LDAP connection
                         </para>
+                        <para>
+                            Example: dyndns_iface = em1, vnet1, vnet2
+                        </para>
                     </listitem>
                 </varlistentry>
 
diff --git a/src/man/sssd-ipa.5.xml b/src/man/sssd-ipa.5.xml
index 0716b6235f93965170983856b930799bfded6258..ca59ffbb005a6f4129362276ce57faa6a9e1af5c 100644
--- a/src/man/sssd-ipa.5.xml
+++ b/src/man/sssd-ipa.5.xml
@@ -166,11 +166,11 @@
                     <listitem>
                         <para>
                             Optional. Applicable only when dyndns_update
-                            is true. Choose the interface whose IP address
+                            is true. Choose the interfaces whose IP addresses
                             should be used for dynamic DNS updates.
                         </para>
                         <para>
-                            NOTE: This option currently supports only one interface.
+                            NOTE: This option currently supports multiple interfaces.
                         </para>
                         <para>
                             NOTE: While it is still possible to use the old
@@ -181,6 +181,9 @@
                         <para>
                             Default: Use the IP address of the IPA LDAP connection
                         </para>
+                        <para>
+                            Example: dyndns_iface = em1, vnet1, vnet2
+                        </para>
                     </listitem>
                 </varlistentry>
 
diff --git a/src/providers/dp_dyndns.c b/src/providers/dp_dyndns.c
index 9552e83d8d4ba615c157c9bae275c8ab867ec274..dec521054e18e083ba0557dbf9c8bfe918d4575e 100644
--- a/src/providers/dp_dyndns.c
+++ b/src/providers/dp_dyndns.c
@@ -49,6 +49,12 @@ struct sss_iface_addr {
     struct sockaddr_storage *addr;
 };
 
+void sss_iface_addr_concatenate(struct sss_iface_addr **list,
+                                struct sss_iface_addr *list2)
+{
+    DLIST_CONCATENATE((*list), list2, struct sss_iface_addr*);
+}
+
 struct sss_iface_addr *
 sss_iface_addr_add(TALLOC_CTX *mem_ctx, struct sss_iface_addr **list,
                    struct sockaddr_storage *ss)
diff --git a/src/providers/dp_dyndns.h b/src/providers/dp_dyndns.h
index 23b833dace58a0ecbb1e2e21963a55186f1d06a8..deba112538ad22cd7f59be07934778ee9d4361e7 100644
--- a/src/providers/dp_dyndns.h
+++ b/src/providers/dp_dyndns.h
@@ -128,4 +128,8 @@ nsupdate_get_addrs_recv(struct tevent_req *req,
                         struct sss_iface_addr **_addrlist,
                         size_t *_count);
 
+void
+sss_iface_addr_concatenate(struct sss_iface_addr **list,
+                           struct sss_iface_addr *list2);
+
 #endif /* DP_DYNDNS_H_ */
diff --git a/src/providers/ldap/sdap_dyndns.c b/src/providers/ldap/sdap_dyndns.c
index bb98f8e1ec6852b04e9ea3e8d5807fecc7e6958d..fd47429b2b05b45a78e6552e62e388ece2e16eb4 100644
--- a/src/providers/ldap/sdap_dyndns.c
+++ b/src/providers/ldap/sdap_dyndns.c
@@ -482,6 +482,65 @@ static void sdap_dyndns_get_addrs_done(struct tevent_req *subreq);
 static errno_t sdap_dyndns_add_ldap_conn(struct sdap_dyndns_get_addrs_state *state,
                                          struct sdap_handle *sh);
 
+static errno_t get_ifaces_addrs(TALLOC_CTX *mem_ctx,
+                                const char *iface,
+                                struct sss_iface_addr **_result)
+{
+    struct sss_iface_addr *result_addrs = NULL;
+    struct sss_iface_addr *intf_addrs;
+    TALLOC_CTX *tmp_ctx;
+    char **list_of_intfs;
+    int num_of_intfs;
+    errno_t ret;
+    int i;
+
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL) {
+        ret = ENOENT;
+        goto done;
+    }
+
+    ret = split_on_separator(tmp_ctx, iface, ',', true, true, &list_of_intfs,
+                             &num_of_intfs);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_MINOR_FAILURE,
+              "Parsing names of interfaces failed - %d:[%s].\n",
+              ret, sss_strerror(ret));
+        goto done;
+    }
+
+    for (i = 0; i < num_of_intfs; i++) {
+        ret = sss_iface_addr_list_get(tmp_ctx, list_of_intfs[i], &intf_addrs);
+        if (ret == EOK) {
+            if (result_addrs != NULL) {
+                /* If there is already an existing list, head of this existing
+                 * list will be considered as parent talloc context for the
+                 * new list.
+                 */
+                talloc_steal(result_addrs, intf_addrs);
+            }
+            sss_iface_addr_concatenate(&result_addrs, intf_addrs);
+        } else if (ret == ENOENT) {
+            /* non-critical failure */
+            DEBUG(SSSDBG_OP_FAILURE,
+                  "Cannot get interface %s or there are no addresses "
+                  "bind to it.\n", list_of_intfs[i]);
+        } else {
+            DEBUG(SSSDBG_OP_FAILURE,
+                  "Cannot get list of addresses from interface %s - %d:[%s]\n",
+                  list_of_intfs[i], ret, sss_strerror(ret));
+            goto done;
+        }
+    }
+
+    ret = EOK;
+
+done:
+    *_result = talloc_steal(mem_ctx, result_addrs);
+    talloc_free(tmp_ctx);
+    return ret;
+}
+
 static struct tevent_req *
 sdap_dyndns_get_addrs_send(TALLOC_CTX *mem_ctx,
                            struct tevent_context *ev,
@@ -500,14 +559,11 @@ sdap_dyndns_get_addrs_send(TALLOC_CTX *mem_ctx,
     }
 
     if (iface) {
-        ret = sss_iface_addr_list_get(state, iface, &state->addresses);
-        if (ret != EOK) {
-            DEBUG(SSSDBG_OP_FAILURE,
-                  "Cannot get list of addresses from interface %s\n", iface);
-            /* non critical failure */
-            if (ret == ENOENT) {
-                ret = EOK;
-            }
+        ret = get_ifaces_addrs(state, iface, &state->addresses);
+        if (ret != EOK || state->addresses == NULL) {
+            DEBUG(SSSDBG_MINOR_FAILURE,
+                  "get_ifaces_addrs() failed: %d:[%s]\n",
+                  ret, sss_strerror(ret));
         }
         /* We're done. Just fake an async request completion */
         goto done;
-- 
2.4.3

