Blame SOURCES/0090-DDNS-execute-nsupdate-for-single-update-of-PTR-rec.patch

6cf099
From 514240c29da65f8bbfc6d17e225655a5ac0f1b3c Mon Sep 17 00:00:00 2001
6cf099
From: Pavel Reichl <preichl@redhat.com>
6cf099
Date: Sat, 12 Sep 2015 09:09:35 -0400
6cf099
Subject: [PATCH 90/90] DDNS: execute nsupdate for single update of PTR rec
6cf099
6cf099
nsupdate fails definitely if any of update request fails when GSSAPI is used.
6cf099
6cf099
As tmp solution nsupdate is executed for each update.
6cf099
6cf099
Resolves:
6cf099
https://fedorahosted.org/sssd/ticket/2783
6cf099
6cf099
Reviewed-by: Jakub Hrozek <jhrozek@redhat.com>
6cf099
(cherry picked from commit eeac17ebbe38f16deaa8599231cccfc97aaac85c)
6cf099
---
6cf099
 src/providers/dp_dyndns.c        | 128 ++++++++++++++++++++-------------------
6cf099
 src/providers/dp_dyndns.h        |  13 +++-
6cf099
 src/providers/ldap/sdap_dyndns.c | 121 ++++++++++++++++++++++++++++++++++--
6cf099
 src/tests/cmocka/test_dyndns.c   |  29 +++++++++
6cf099
 4 files changed, 219 insertions(+), 72 deletions(-)
6cf099
6cf099
diff --git a/src/providers/dp_dyndns.c b/src/providers/dp_dyndns.c
6cf099
index 0577743cb2daca9c0e86b5beb6bf059ee7b5783f..50b087446f9437466de355e4d72b39a69512da03 100644
6cf099
--- a/src/providers/dp_dyndns.c
6cf099
+++ b/src/providers/dp_dyndns.c
6cf099
@@ -52,6 +52,25 @@ struct sss_iface_addr {
6cf099
     struct sockaddr_storage *addr;
6cf099
 };
6cf099
 
6cf099
+struct sockaddr_storage*
6cf099
+sss_iface_addr_get_address(struct sss_iface_addr *address)
6cf099
+{
6cf099
+    if (address == NULL) {
6cf099
+        return NULL;
6cf099
+    }
6cf099
+
6cf099
+    return address->addr;
6cf099
+}
6cf099
+
6cf099
+struct sss_iface_addr *sss_iface_addr_get_next(struct sss_iface_addr *address)
6cf099
+{
6cf099
+    if (address) {
6cf099
+        return address->next;
6cf099
+    }
6cf099
+
6cf099
+    return NULL;
6cf099
+}
6cf099
+
6cf099
 void sss_iface_addr_concatenate(struct sss_iface_addr **list,
6cf099
                                 struct sss_iface_addr *list2)
6cf099
 {
6cf099
@@ -293,80 +312,63 @@ nsupdate_msg_add_fwd(char *update_msg, struct sss_iface_addr *addresses,
6cf099
     return talloc_asprintf_append(update_msg, "send\n");
6cf099
 }
6cf099
 
6cf099
-static char *
6cf099
-nsupdate_msg_add_ptr(char *update_msg, struct sss_iface_addr *addresses,
6cf099
-                     const char *hostname, int ttl, uint8_t remove_af,
6cf099
-                     struct sss_iface_addr *old_addresses)
6cf099
+static uint8_t *nsupdate_convert_address(struct sockaddr_storage *add_address)
6cf099
+{
6cf099
+    uint8_t *addr;
6cf099
+
6cf099
+    switch(add_address->ss_family) {
6cf099
+    case AF_INET:
6cf099
+        addr = (uint8_t *) &((struct sockaddr_in *) add_address)->sin_addr;
6cf099
+        break;
6cf099
+    case AF_INET6:
6cf099
+        addr = (uint8_t *) &((struct sockaddr_in6 *) add_address)->sin6_addr;
6cf099
+        break;
6cf099
+    default:
6cf099
+        DEBUG(SSSDBG_CRIT_FAILURE, "Unknown address family\n");
6cf099
+        addr = NULL;
6cf099
+        break;
6cf099
+    }
6cf099
+
6cf099
+    return addr;
6cf099
+}
6cf099
+
6cf099
+static char *nsupdate_msg_add_ptr(char *update_msg,
6cf099
+                                  struct sockaddr_storage *address,
6cf099
+                                  const char *hostname,
6cf099
+                                  int ttl,
6cf099
+                                  bool delete)
6cf099
 {
6cf099
-    struct sss_iface_addr *new_record, *old_record;
6cf099
     char *strptr;
6cf099
     uint8_t *addr;
6cf099
 
6cf099
-    DLIST_FOR_EACH(old_record, old_addresses) {
6cf099
-        switch(old_record->addr->ss_family) {
6cf099
-        case AF_INET:
6cf099
-            if (!(remove_af & DYNDNS_REMOVE_A)) {
6cf099
-                continue;
6cf099
-            }
6cf099
-            addr = (uint8_t *) &((struct sockaddr_in *) old_record->addr)->sin_addr;
6cf099
-            break;
6cf099
-        case AF_INET6:
6cf099
-            if (!(remove_af & DYNDNS_REMOVE_AAAA)) {
6cf099
-                continue;
6cf099
-            }
6cf099
-            addr = (uint8_t *) &((struct sockaddr_in6 *) old_record->addr)->sin6_addr;
6cf099
-            break;
6cf099
-        default:
6cf099
-            DEBUG(SSSDBG_CRIT_FAILURE, "Unknown address family\n");
6cf099
-            return NULL;
6cf099
-        }
6cf099
+    addr = nsupdate_convert_address(address);
6cf099
+    if (addr == NULL) {
6cf099
+        return NULL;
6cf099
+    }
6cf099
 
6cf099
-        strptr = resolv_get_string_ptr_address(update_msg, old_record->addr->ss_family,
6cf099
-                                               addr);
6cf099
-        if (strptr == NULL) {
6cf099
-            return NULL;
6cf099
-        }
6cf099
+    strptr = resolv_get_string_ptr_address(update_msg, address->ss_family,
6cf099
+                                           addr);
6cf099
+    if (strptr == NULL) {
6cf099
+        return NULL;
6cf099
+    }
6cf099
 
6cf099
+    if (delete) {
6cf099
         /* example: update delete 38.78.16.10.in-addr.arpa. in PTR */
6cf099
         update_msg = talloc_asprintf_append(update_msg,
6cf099
                                             "update delete %s in PTR\n"
6cf099
                                             "send\n",
6cf099
                                             strptr);
6cf099
-        talloc_free(strptr);
6cf099
-        if (update_msg == NULL) {
6cf099
-            return NULL;
6cf099
-        }
6cf099
-    }
6cf099
-
6cf099
-    /* example: update add 11.78.16.10.in-addr.arpa. 85000 in PTR testvm.example.com */
6cf099
-    DLIST_FOR_EACH(new_record, addresses) {
6cf099
-        switch(new_record->addr->ss_family) {
6cf099
-        case AF_INET:
6cf099
-            addr = (uint8_t *) &((struct sockaddr_in *) new_record->addr)->sin_addr;
6cf099
-            break;
6cf099
-        case AF_INET6:
6cf099
-            addr = (uint8_t *) &((struct sockaddr_in6 *) new_record->addr)->sin6_addr;
6cf099
-            break;
6cf099
-        default:
6cf099
-            DEBUG(SSSDBG_CRIT_FAILURE, "Unknown address family\n");
6cf099
-            return NULL;
6cf099
-        }
6cf099
-
6cf099
-        strptr = resolv_get_string_ptr_address(update_msg, new_record->addr->ss_family,
6cf099
-                                               addr);
6cf099
-        if (strptr == NULL) {
6cf099
-            return NULL;
6cf099
-        }
6cf099
-
6cf099
+    } else {
6cf099
         /* example: update delete 38.78.16.10.in-addr.arpa. in PTR */
6cf099
         update_msg = talloc_asprintf_append(update_msg,
6cf099
                                             "update add %s %d in PTR %s.\n"
6cf099
                                             "send\n",
6cf099
                                             strptr, ttl, hostname);
6cf099
-        talloc_free(strptr);
6cf099
-        if (update_msg == NULL) {
6cf099
-            return NULL;
6cf099
-        }
6cf099
+    }
6cf099
+
6cf099
+    talloc_free(strptr);
6cf099
+    if (update_msg == NULL) {
6cf099
+        return NULL;
6cf099
     }
6cf099
 
6cf099
     return update_msg;
6cf099
@@ -471,9 +473,9 @@ done:
6cf099
 errno_t
6cf099
 be_nsupdate_create_ptr_msg(TALLOC_CTX *mem_ctx, const char *realm,
6cf099
                            const char *servername, const char *hostname,
6cf099
-                           const unsigned int ttl, uint8_t remove_af,
6cf099
-                           struct sss_iface_addr *addresses,
6cf099
-                           struct sss_iface_addr *old_addresses,
6cf099
+                           const unsigned int ttl,
6cf099
+                           struct sockaddr_storage *address,
6cf099
+                           bool delete,
6cf099
                            char **_update_msg)
6cf099
 {
6cf099
     errno_t ret;
6cf099
@@ -490,8 +492,8 @@ be_nsupdate_create_ptr_msg(TALLOC_CTX *mem_ctx, const char *realm,
6cf099
         goto done;
6cf099
     }
6cf099
 
6cf099
-    update_msg = nsupdate_msg_add_ptr(update_msg, addresses, hostname,
6cf099
-                                      ttl, remove_af, old_addresses);
6cf099
+    update_msg = nsupdate_msg_add_ptr(update_msg, address, hostname, ttl,
6cf099
+                                      delete);
6cf099
     if (update_msg == NULL) {
6cf099
         ret = ENOMEM;
6cf099
         goto done;
6cf099
diff --git a/src/providers/dp_dyndns.h b/src/providers/dp_dyndns.h
6cf099
index 9f72331b6fd68e17e9eb91505a13fc839d3f54e1..9f39e5d48ed46e69d4052f2139ea5f13b9e5d12c 100644
6cf099
--- a/src/providers/dp_dyndns.h
6cf099
+++ b/src/providers/dp_dyndns.h
6cf099
@@ -97,9 +97,9 @@ be_nsupdate_create_fwd_msg(TALLOC_CTX *mem_ctx, const char *realm,
6cf099
 errno_t
6cf099
 be_nsupdate_create_ptr_msg(TALLOC_CTX *mem_ctx, const char *realm,
6cf099
                            const char *servername, const char *hostname,
6cf099
-                           const unsigned int ttl, uint8_t remove_af,
6cf099
-                           struct sss_iface_addr *addresses,
6cf099
-                           struct sss_iface_addr *old_addresses,
6cf099
+                           const unsigned int ttl,
6cf099
+                           struct sockaddr_storage *address,
6cf099
+                           bool delete,
6cf099
                            char **_update_msg);
6cf099
 
6cf099
 /* Returns:
6cf099
@@ -133,4 +133,11 @@ errno_t
6cf099
 sss_get_dualstack_addresses(TALLOC_CTX *mem_ctx,
6cf099
                             struct sockaddr *ss,
6cf099
                             struct sss_iface_addr **_iface_addrs);
6cf099
+
6cf099
+struct sss_iface_addr *
6cf099
+sss_iface_addr_get_next(struct sss_iface_addr *address);
6cf099
+
6cf099
+struct sockaddr_storage*
6cf099
+sss_iface_addr_get_address(struct sss_iface_addr *address);
6cf099
+
6cf099
 #endif /* DP_DYNDNS_H_ */
6cf099
diff --git a/src/providers/ldap/sdap_dyndns.c b/src/providers/ldap/sdap_dyndns.c
6cf099
index 2a179fd1b5e88bdf2442657ff6fa1dcc55417467..3a52a11d1e1c86ee7b26cf6affd81f7cf1bb7d03 100644
6cf099
--- a/src/providers/ldap/sdap_dyndns.c
6cf099
+++ b/src/providers/ldap/sdap_dyndns.c
6cf099
@@ -60,6 +60,8 @@ struct sdap_dyndns_update_state {
6cf099
     enum be_nsupdate_auth auth_type;
6cf099
     bool fallback_mode;
6cf099
     char *update_msg;
6cf099
+    struct sss_iface_addr *ptr_addr_iter;
6cf099
+    bool del_phase;
6cf099
 };
6cf099
 
6cf099
 static void sdap_dyndns_update_addrs_done(struct tevent_req *subreq);
6cf099
@@ -70,6 +72,12 @@ static errno_t sdap_dyndns_update_step(struct tevent_req *req);
6cf099
 static errno_t sdap_dyndns_update_ptr_step(struct tevent_req *req);
6cf099
 static void sdap_dyndns_update_done(struct tevent_req *subreq);
6cf099
 static void sdap_dyndns_update_ptr_done(struct tevent_req *subreq);
6cf099
+static errno_t
6cf099
+sdap_dyndns_next_ptr_record(struct sdap_dyndns_update_state *state,
6cf099
+                            struct tevent_req *req);
6cf099
+static struct sss_iface_addr*
6cf099
+sdap_get_address_to_delete(struct sss_iface_addr *address_it,
6cf099
+                           uint8_t remove_af);
6cf099
 
6cf099
 struct tevent_req *
6cf099
 sdap_dyndns_update_send(TALLOC_CTX *mem_ctx,
6cf099
@@ -106,6 +114,8 @@ sdap_dyndns_update_send(TALLOC_CTX *mem_ctx,
6cf099
     state->ev = ev;
6cf099
     state->opts = opts;
6cf099
     state->auth_type = auth_type;
6cf099
+    state->ptr_addr_iter = NULL;
6cf099
+    state->del_phase = true;
6cf099
 
6cf099
     /* fallback servername is overriden by user option */
6cf099
     conf_servername = dp_opt_get_string(opts, DP_OPT_DYNDNS_SERVER);
6cf099
@@ -381,6 +391,16 @@ sdap_dyndns_update_done(struct tevent_req *subreq)
6cf099
     }
6cf099
 
6cf099
     talloc_free(state->update_msg);
6cf099
+
6cf099
+    /* init iterator for addresses to be deleted */
6cf099
+    state->ptr_addr_iter = sdap_get_address_to_delete(state->dns_addrlist,
6cf099
+                                                      state->remove_af);
6cf099
+    if (state->ptr_addr_iter == NULL) {
6cf099
+        /* init iterator for addresses to be added */
6cf099
+        state->del_phase = false;
6cf099
+        state->ptr_addr_iter = state->addresses;
6cf099
+    }
6cf099
+
6cf099
     ret = sdap_dyndns_update_ptr_step(req);
6cf099
     if (ret != EOK) {
6cf099
         tevent_req_error(req, ret);
6cf099
@@ -389,6 +409,50 @@ sdap_dyndns_update_done(struct tevent_req *subreq)
6cf099
     /* Execution will resume in sdap_dyndns_update_ptr_done */
6cf099
 }
6cf099
 
6cf099
+
6cf099
+static bool remove_addr(int address_family, uint8_t remove_af)
6cf099
+{
6cf099
+    bool ret = false;
6cf099
+
6cf099
+    switch(address_family) {
6cf099
+    case AF_INET:
6cf099
+        if (remove_af & DYNDNS_REMOVE_A) {
6cf099
+            ret = true;
6cf099
+        }
6cf099
+        break;
6cf099
+    case AF_INET6:
6cf099
+        if (remove_af & DYNDNS_REMOVE_AAAA) {
6cf099
+            ret = true;
6cf099
+        }
6cf099
+        break;
6cf099
+    default:
6cf099
+        DEBUG(SSSDBG_CRIT_FAILURE, "Unknown address family\n");
6cf099
+        ret = false;
6cf099
+    }
6cf099
+
6cf099
+    return ret;
6cf099
+}
6cf099
+
6cf099
+static struct sss_iface_addr*
6cf099
+sdap_get_address_to_delete(struct sss_iface_addr *address_it,
6cf099
+                           uint8_t remove_af)
6cf099
+{
6cf099
+    struct sockaddr_storage* address;
6cf099
+
6cf099
+    while (address_it != NULL) {
6cf099
+        address = sss_iface_addr_get_address(address_it);
6cf099
+
6cf099
+        /* skip addresses that are not to be deleted */
6cf099
+        if (remove_addr(address->ss_family, remove_af)) {
6cf099
+            break;
6cf099
+        }
6cf099
+
6cf099
+        address_it = sss_iface_addr_get_next(address_it);
6cf099
+    }
6cf099
+
6cf099
+    return address_it;
6cf099
+}
6cf099
+
6cf099
 static errno_t
6cf099
 sdap_dyndns_update_ptr_step(struct tevent_req *req)
6cf099
 {
6cf099
@@ -396,6 +460,7 @@ sdap_dyndns_update_ptr_step(struct tevent_req *req)
6cf099
     struct sdap_dyndns_update_state *state;
6cf099
     const char *servername;
6cf099
     struct tevent_req *subreq;
6cf099
+    struct sockaddr_storage *address;
6cf099
 
6cf099
     state = tevent_req_data(req, struct sdap_dyndns_update_state);
6cf099
 
6cf099
@@ -405,11 +470,14 @@ sdap_dyndns_update_ptr_step(struct tevent_req *req)
6cf099
         servername = state->servername;
6cf099
     }
6cf099
 
6cf099
-    ret = be_nsupdate_create_ptr_msg(state, state->realm,
6cf099
-                                     servername, state->hostname,
6cf099
-                                     state->ttl, state->remove_af,
6cf099
-                                     state->addresses, state->dns_addrlist,
6cf099
-                                     &state->update_msg);
6cf099
+    address = sss_iface_addr_get_address(state->ptr_addr_iter);
6cf099
+    if (address == NULL) {
6cf099
+        return EIO;
6cf099
+    }
6cf099
+
6cf099
+    ret = be_nsupdate_create_ptr_msg(state, state->realm, servername,
6cf099
+                                     state->hostname, state->ttl, address,
6cf099
+                                     state->del_phase, &state->update_msg);
6cf099
     if (ret != EOK) {
6cf099
         DEBUG(SSSDBG_OP_FAILURE, "Can't get addresses for DNS update\n");
6cf099
         return ret;
6cf099
@@ -454,13 +522,55 @@ sdap_dyndns_update_ptr_done(struct tevent_req *subreq)
6cf099
             }
6cf099
         }
6cf099
 
6cf099
+        ret = sdap_dyndns_next_ptr_record(state, req);
6cf099
+        if (ret == EAGAIN) {
6cf099
+            return;
6cf099
+        }
6cf099
+
6cf099
         tevent_req_error(req, ret);
6cf099
         return;
6cf099
     }
6cf099
 
6cf099
+    ret = sdap_dyndns_next_ptr_record(state, req);
6cf099
+    if (ret == EAGAIN) {
6cf099
+        return;
6cf099
+    }
6cf099
+
6cf099
     tevent_req_done(req);
6cf099
 }
6cf099
 
6cf099
+static errno_t
6cf099
+sdap_dyndns_next_ptr_record(struct sdap_dyndns_update_state *state,
6cf099
+                            struct tevent_req *req)
6cf099
+{
6cf099
+    errno_t ret;
6cf099
+
6cf099
+    if (state->del_phase) {
6cf099
+        /* iterate to next address to delete */
6cf099
+        state->ptr_addr_iter = sdap_get_address_to_delete(
6cf099
+            sss_iface_addr_get_next(state->ptr_addr_iter), state->remove_af);
6cf099
+        if (state->ptr_addr_iter == NULL) {
6cf099
+            /* init iterator for addresses to be added */
6cf099
+            state->del_phase = false;
6cf099
+            state->ptr_addr_iter = state->addresses;
6cf099
+        }
6cf099
+    } else {
6cf099
+        /* iterate to next address to add */
6cf099
+        state->ptr_addr_iter = sss_iface_addr_get_next(state->ptr_addr_iter);
6cf099
+    }
6cf099
+
6cf099
+    if (state->ptr_addr_iter != NULL) {
6cf099
+
6cf099
+        state->fallback_mode = false;
6cf099
+        ret = sdap_dyndns_update_ptr_step(req);
6cf099
+        if (ret == EOK) {
6cf099
+            return EAGAIN;
6cf099
+        }
6cf099
+    }
6cf099
+
6cf099
+    return EOK;
6cf099
+}
6cf099
+
6cf099
 errno_t
6cf099
 sdap_dyndns_update_recv(struct tevent_req *req)
6cf099
 {
6cf099
@@ -755,7 +865,6 @@ fail:
6cf099
     return req;
6cf099
 }
6cf099
 
6cf099
-
6cf099
 static void
6cf099
 sdap_dyndns_timer_conn_done(struct tevent_req *subreq)
6cf099
 {
6cf099
diff --git a/src/tests/cmocka/test_dyndns.c b/src/tests/cmocka/test_dyndns.c
6cf099
index 8118e9438e89465674155c11f4523d2313f6a59c..0a2fd1227c84c7783207444e21269026d268f993 100644
6cf099
--- a/src/tests/cmocka/test_dyndns.c
6cf099
+++ b/src/tests/cmocka/test_dyndns.c
6cf099
@@ -200,6 +200,32 @@ void will_return_getifaddrs(const char *ifname, const char *straddr,
6cf099
     }
6cf099
 }
6cf099
 
6cf099
+void dyndns_test_sss_iface_addr_get_misc(void **state)
6cf099
+{
6cf099
+    struct sss_iface_addr addrs[3];
6cf099
+    struct sockaddr_storage ss[3];
6cf099
+
6cf099
+    addrs[0].prev = NULL;
6cf099
+    addrs[0].next = &addrs[1];
6cf099
+    addrs[0].addr = &ss[0];
6cf099
+    addrs[1].prev = &addrs[0];
6cf099
+    addrs[1].next = &addrs[2];
6cf099
+    addrs[1].addr = &ss[1];
6cf099
+    addrs[2].prev = &addrs[1];
6cf099
+    addrs[2].next = NULL;
6cf099
+    addrs[2].addr = &ss[2];
6cf099
+
6cf099
+    assert_ptr_equal(sss_iface_addr_get_address(NULL), NULL);
6cf099
+    assert_ptr_equal(sss_iface_addr_get_address(&addrs[0]), &ss[0]);
6cf099
+    assert_ptr_equal(sss_iface_addr_get_address(&addrs[1]), &ss[1]);
6cf099
+    assert_ptr_equal(sss_iface_addr_get_address(&addrs[2]), &ss[2]);
6cf099
+
6cf099
+    assert_ptr_equal(sss_iface_addr_get_next(NULL), NULL);
6cf099
+    assert_ptr_equal(sss_iface_addr_get_next(&addrs[0]), &addrs[1]);
6cf099
+    assert_ptr_equal(sss_iface_addr_get_next(&addrs[1]), &addrs[2]);
6cf099
+    assert_ptr_equal(sss_iface_addr_get_next(&addrs[2]), NULL);
6cf099
+}
6cf099
+
6cf099
 void dyndns_test_get_ifaddr(void **state)
6cf099
 {
6cf099
     errno_t ret;
6cf099
@@ -663,6 +689,9 @@ int main(int argc, const char *argv[])
6cf099
 
6cf099
     const struct CMUnitTest tests[] = {
6cf099
         /* Utility functions unit test */
6cf099
+        cmocka_unit_test_setup_teardown(dyndns_test_sss_iface_addr_get_misc,
6cf099
+                                        dyndns_test_simple_setup,
6cf099
+                                        dyndns_test_teardown),
6cf099
         cmocka_unit_test_setup_teardown(dyndns_test_get_ifaddr,
6cf099
                                         dyndns_test_simple_setup,
6cf099
                                         dyndns_test_teardown),
6cf099
-- 
6cf099
2.4.3
6cf099