-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 12/02/2009 03:07 PM, Martin Nagy wrote:
> 
> I think we should just push these patches (after the review is done) and
> then disable them in the build & configure system like Stephen did for
> ELAPI (although FWIW, I think it would be nice to keep the tests
> running).
> 

OK, I just think this should be a separate patch - hence 0003.

>> [PATCH 1/2] Change ares usage to be c-ares 1.7.0 compatible
>> * Rename structure accordingly to ares upstream
>> * Use new ares parsing functions in the wrappers
>> * fix tests for ares 1.7
> 
>>From rewrite_talloc_srv_reply():
> +        if (ptr->host == NULL) {
> +            talloc_free(ptr);
>              return ENOMEM;
>          }
> +
> I believe this should be talloc_free(new_list), otherwise you might try
> to free a pointer pointing into middle of a talloc'ed memory. Also, is

Thanks, fixed.

> it wise to allocate an array for a linked list? I would recommend
> allocating each list item separately using mem_ctx and maybe provide a
> free function that would free all the items.

OK, each item is now allocated using talloc_zero in the loop. I just
think the other items including the SRV/TXT payload should be allocated
using new_list as a context, that way you can just talloc_free(new_list).

> 
> +        ptr = ptr->next;
> +        old_list = old_list->next;
> This is also bad, since ptr->next is not initialized.
> 

For whatever reason I thought talloc_array was using talloc_zero under
the hood. Using talloc_zero for every item separately now takes care of it.

> Same goes for rewrite_talloc_txt_reply().
> 

Also fixed.

>> [PATCH 2/2] Import ares 1.7.0 helpers
>> Synchronizes the bundled helpers with the changes done during the c-ares
>> 1.7.0 development in order for the SRV and TXT parsing routines to work
>> also with pre-1.7.0 ares versions.
> 
> Sorry, I didn't yet have time to review it, I will do it later (tomorrow
> probably).

The attached patch 0002 fixes the issue you outlined in the other reply
to the thread.

        Jakub
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/

iEYEARECAAYFAksdUXQACgkQHsardTLnvCVifgCgnGX25X2yxF/FMLh9KtAiYnZB
lTEAnRrWvivyOrCEOrsZsBFfdIZ/dDhy
=Va/X
-----END PGP SIGNATURE-----
>From 478cfade9f57ff0ee991a6eecff0ec5a7ced3bff Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhro...@redhat.com>
Date: Tue, 3 Nov 2009 16:24:25 +0100
Subject: [PATCH 1/3] Change ares usage to be c-ares 1.7.0 compatible

* Rename structure accordingly to ares upstream
* Use new ares parsing functions in the wrappers
* fix tests for ares 1.7
---
 server/resolv/async_resolv.c |  128 +++++++++++++++++++++---------------------
 server/resolv/async_resolv.h |    6 +-
 server/tests/resolv-tests.c  |   26 ++++-----
 3 files changed, 77 insertions(+), 83 deletions(-)

diff --git a/server/resolv/async_resolv.c b/server/resolv/async_resolv.c
index 6ac5e41..51f981a 100644
--- a/server/resolv/async_resolv.c
+++ b/server/resolv/async_resolv.c
@@ -43,13 +43,13 @@
 #include "util/util.h"
 
 #ifndef HAVE_ARES_PARSE_SRV
-#define ares_parse_srv_reply(abuf, alen, srv_out, nsrvreply) \
-    _ares_parse_srv_reply(abuf, alen, srv_out, nsrvreply)
+#define ares_parse_srv_reply(abuf, alen, srv_out) \
+    _ares_parse_srv_reply(abuf, alen, srv_out)
 #endif /* HAVE_ARES_PARSE_SRV */
 
 #ifndef HAVE_ARES_PARSE_TXT
-#define ares_parse_txt_reply(abuf, alen, txt_out, ntxtreply) \
-    _ares_parse_txt_reply(abuf, alen, txt_out, ntxtreply)
+#define ares_parse_txt_reply(abuf, alen, txt_out) \
+    _ares_parse_txt_reply(abuf, alen, txt_out)
 #endif /* HAVE_ARES_PARSE_TXT */
 
 struct fd_watch {
@@ -442,40 +442,48 @@ ares_gethostbyname_wakeup(struct tevent_req *subreq)
 }
 
 /*
- * A simple helper function that will take an array of struct srv_reply that
+ * A simple helper function that will take an array of struct ares_srv_reply that
  * was allocated by malloc() in c-ares and copies it using talloc. The old one
  * is freed and the talloc one is put into 'reply_list' instead.
  */
 static int
-rewrite_talloc_srv_reply(TALLOC_CTX *mem_ctx, struct srv_reply **reply_list,
-                         int num_replies)
+rewrite_talloc_srv_reply(TALLOC_CTX *mem_ctx, struct ares_srv_reply **reply_list)
 {
-    int i;
-    struct srv_reply *new_list;
-    struct srv_reply *old_list = *reply_list;
+    struct ares_srv_reply *ptr;
+    struct ares_srv_reply *new_list;
+    struct ares_srv_reply *old_list = *reply_list;
 
-    new_list = talloc_array(mem_ctx, struct srv_reply, num_replies);
+    new_list = talloc_zero(mem_ctx, struct ares_srv_reply);
     if (new_list == NULL) {
         return ENOMEM;
     }
+    ptr = new_list;
+
+    /* Copy the linked list */
+    while (old_list) {
+        if (!ptr) {
+            ptr = talloc_zero(new_list, struct ares_srv_reply);
+            if (ptr == NULL) {
+                talloc_free(new_list);
+                return ENOMEM;
+            }
+        }
 
-    /* Copy the new_list array. */
-    for (i = 0; i < num_replies; i++) {
-        new_list[i].weight = old_list[i].weight;
-        new_list[i].priority = old_list[i].priority;
-        new_list[i].port = old_list[i].port;
-        new_list[i].host = talloc_strdup(new_list, old_list[i].host);
-        if (new_list[i].host == NULL) {
+        ptr->weight = old_list->weight;
+        ptr->priority = old_list->priority;
+        ptr->port = old_list->port;
+        ptr->host = talloc_strdup(new_list, old_list->host);
+        if (ptr->host == NULL) {
             talloc_free(new_list);
             return ENOMEM;
         }
+
+        ptr = ptr->next;
+        old_list = old_list->next;
     }
 
     /* Free the old one (uses malloc). */
-    for (i = 0; i < num_replies; i++) {
-        free(old_list[i].host);
-    }
-    free(old_list);
+    ares_free_data(reply_list);
 
     /* And now put our own new_list in place. */
     *reply_list = new_list;
@@ -493,8 +501,7 @@ struct getsrv_state {
     const char *query;
 
     /* parsed data returned by ares */
-    struct srv_reply *reply_list;
-    int num_replies;
+    struct ares_srv_reply *reply_list;
     int status;
     int timeouts;
 };
@@ -522,7 +529,6 @@ resolv_getsrv_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
     state->resolv_ctx = ctx;
     state->query = query;
     state->reply_list = NULL;
-    state->num_replies = 0;
     state->status = 0;
     state->timeouts = 0;
 
@@ -543,8 +549,7 @@ resolv_getsrv_done(void *arg, int status, int timeouts, unsigned char *abuf, int
     struct tevent_req *req = talloc_get_type(arg, struct tevent_req);
     struct getsrv_state *state = tevent_req_data(req, struct getsrv_state);
     int ret;
-    int num_replies;
-    struct srv_reply *reply_list;
+    struct ares_srv_reply *reply_list;
 
     state->status = status;
     state->timeouts = timeouts;
@@ -555,32 +560,29 @@ resolv_getsrv_done(void *arg, int status, int timeouts, unsigned char *abuf, int
         goto fail;
     }
 
-    ret = ares_parse_srv_reply(abuf, alen, &reply_list, &num_replies);
+    ret = ares_parse_srv_reply(abuf, alen, &reply_list);
     if (status != ARES_SUCCESS) {
         DEBUG(2, ("SRV record parsing failed: %d: %s\n", ret, ares_strerror(ret)));
         ret = return_code(ret);
         goto fail;
     }
-    ret = rewrite_talloc_srv_reply(req, &reply_list, num_replies);
+    ret = rewrite_talloc_srv_reply(req, &reply_list);
     if (ret != EOK) {
         goto fail;
     }
     state->reply_list = reply_list;
-    state->num_replies = num_replies;
 
     tevent_req_done(req);
     return;
 
 fail:
     state->reply_list = NULL;
-    state->num_replies = 0;
     tevent_req_error(req, ret);
 }
 
 int
 resolv_getsrv_recv(TALLOC_CTX *mem_ctx, struct tevent_req *req, int *status,
-                   int *timeouts, struct srv_reply **reply_list,
-                   int *num_replies)
+                   int *timeouts, struct ares_srv_reply **reply_list)
 {
     struct getsrv_state *state = tevent_req_data(req, struct getsrv_state);
 
@@ -590,8 +592,6 @@ resolv_getsrv_recv(TALLOC_CTX *mem_ctx, struct tevent_req *req, int *status,
         *timeouts = state->timeouts;
     if (reply_list)
         *reply_list = talloc_steal(mem_ctx, state->reply_list);
-    if (num_replies)
-        *num_replies = state->num_replies;
 
     TEVENT_REQ_RETURN_ON_ERROR(req);
 
@@ -627,34 +627,40 @@ ares_getsrv_wakeup(struct tevent_req *subreq)
  * is freed and the talloc one is put into 'reply_list' instead.
  */
 static int
-rewrite_talloc_txt_reply(TALLOC_CTX *mem_ctx, struct txt_reply **reply_list,
-                         int num_replies)
+rewrite_talloc_txt_reply(TALLOC_CTX *mem_ctx, struct ares_txt_reply **reply_list)
 {
-    int i;
-    struct txt_reply *new_list;
-    struct txt_reply *old_list = *reply_list;
+    struct ares_txt_reply *ptr;
+    struct ares_txt_reply *new_list;
+    struct ares_txt_reply *old_list = *reply_list;
 
-    new_list = talloc_array(mem_ctx, struct txt_reply, num_replies);
+    new_list = talloc_zero(mem_ctx, struct ares_txt_reply);
     if (new_list == NULL) {
         return ENOMEM;
     }
+    ptr = new_list;
 
-    /* Copy the new_list array. */
-    for (i = 0; i < num_replies; i++) {
-        new_list[i].length = old_list[i].length;
-        new_list[i].txt = talloc_memdup(new_list, old_list[i].txt,
-                                        old_list[i].length);
-        if (new_list[i].txt == NULL) {
+    /* Copy the linked list */
+    while (old_list) {
+        if (!ptr) {
+            ptr = talloc_zero(new_list, struct ares_txt_reply);
+            if (ptr == NULL) {
+                return ENOMEM;
+            }
+        }
+
+        ptr->length = old_list->length;
+        ptr->txt = talloc_memdup(new_list, old_list->txt,
+                                           old_list->length);
+        if (ptr->txt == NULL) {
             talloc_free(new_list);
             return ENOMEM;
         }
-    }
 
-    /* Free the old one (uses malloc). */
-    for (i = 0; i < num_replies; i++) {
-        free(old_list[i].txt);
+        ptr = ptr->next;
+        old_list = old_list->next;
     }
-    free(old_list);
+
+    ares_free_data(reply_list);
 
     /* And now put our own new_list in place. */
     *reply_list = new_list;
@@ -672,8 +678,7 @@ struct gettxt_state {
     const char *query;
 
     /* parsed data returned by ares */
-    struct txt_reply *reply_list;
-    int num_replies;
+    struct ares_txt_reply *reply_list;
     int status;
     int timeouts;
 };
@@ -701,7 +706,6 @@ resolv_gettxt_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
     state->resolv_ctx = ctx;
     state->query = query;
     state->reply_list = NULL;
-    state->num_replies = 0;
     state->status = 0;
     state->timeouts = 0;
 
@@ -723,8 +727,7 @@ resolv_gettxt_done(void *arg, int status, int timeouts, unsigned char *abuf, int
     struct tevent_req *req = talloc_get_type(arg, struct tevent_req);
     struct gettxt_state *state = tevent_req_data(req, struct gettxt_state);
     int ret;
-    int num_replies;
-    struct txt_reply *reply_list;
+    struct ares_txt_reply *reply_list;
 
     state->status = status;
     state->timeouts = timeouts;
@@ -734,32 +737,29 @@ resolv_gettxt_done(void *arg, int status, int timeouts, unsigned char *abuf, int
         goto fail;
     }
 
-    ret = ares_parse_txt_reply(abuf, alen, &reply_list, &num_replies);
+    ret = ares_parse_txt_reply(abuf, alen, &reply_list);
     if (status != ARES_SUCCESS) {
         DEBUG(2, ("TXT record parsing failed: %d: %s\n", ret, ares_strerror(ret)));
         ret = return_code(ret);
         goto fail;
     }
-    ret = rewrite_talloc_txt_reply(req, &reply_list, num_replies);
+    ret = rewrite_talloc_txt_reply(req, &reply_list);
     if (ret != EOK) {
         goto fail;
     }
     state->reply_list = reply_list;
-    state->num_replies = num_replies;
 
     tevent_req_done(req);
     return;
 
 fail:
     state->reply_list = NULL;
-    state->num_replies = 0;
     tevent_req_error(req, ret);
 }
 
 int
 resolv_gettxt_recv(TALLOC_CTX *mem_ctx, struct tevent_req *req, int *status,
-                   int *timeouts, struct txt_reply **reply_list,
-                   int *num_replies)
+                   int *timeouts, struct ares_txt_reply **reply_list)
 {
     struct gettxt_state *state = tevent_req_data(req, struct gettxt_state);
 
@@ -769,8 +769,6 @@ resolv_gettxt_recv(TALLOC_CTX *mem_ctx, struct tevent_req *req, int *status,
         *timeouts = state->timeouts;
     if (reply_list)
         *reply_list = talloc_steal(mem_ctx, state->reply_list);
-    if (num_replies)
-        *num_replies = state->num_replies;
 
     TEVENT_REQ_RETURN_ON_ERROR(req);
 
diff --git a/server/resolv/async_resolv.h b/server/resolv/async_resolv.h
index 702d4dd..9d080ec 100644
--- a/server/resolv/async_resolv.h
+++ b/server/resolv/async_resolv.h
@@ -77,8 +77,7 @@ int resolv_getsrv_recv(TALLOC_CTX *mem_ctx,
                        struct tevent_req *req,
                        int *status,
                        int *timeouts,
-                       struct srv_reply **reply_list,
-                       int *num_replies);
+                       struct ares_srv_reply **reply_list);
 
 /** Get TXT record **/
 struct tevent_req *resolv_gettxt_send(TALLOC_CTX *mem_ctx,
@@ -90,7 +89,6 @@ int resolv_gettxt_recv(TALLOC_CTX *mem_ctx,
                        struct tevent_req *req,
                        int *status,
                        int *timeouts,
-                       struct txt_reply **reply_list,
-                       int *num_replies);
+                       struct ares_txt_reply **reply_list);
 
 #endif /* __ASYNC_RESOLV_H__ */
diff --git a/server/tests/resolv-tests.c b/server/tests/resolv-tests.c
index bf76849..d6b8c4f 100644
--- a/server/tests/resolv-tests.c
+++ b/server/tests/resolv-tests.c
@@ -253,15 +253,13 @@ END_TEST
 
 static void test_internet(struct tevent_req *req)
 {
-    int i;
     int recv_status;
     int status;
     struct resolv_test_ctx *test_ctx;
     void *tmp_ctx;
     struct hostent *hostent = NULL;
-    struct txt_reply *txt_replies = NULL;
-    struct srv_reply *srv_replies = NULL;
-    int count;
+    struct ares_txt_reply *txt_replies = NULL, *txtptr;
+    struct ares_srv_reply *srv_replies = NULL, *srvptr;
 
     test_ctx = tevent_req_callback_data(req, struct resolv_test_ctx);
 
@@ -278,20 +276,20 @@ static void test_internet(struct tevent_req *req)
         break;
     case TESTING_TXT:
         recv_status = resolv_gettxt_recv(tmp_ctx, req, &status, NULL,
-                                         &txt_replies, &count);
-        test_ctx->error = (count == 0) ? ENOENT : EOK;
-        for (i = 0; i < count; i++) {
-            DEBUG(2, ("TXT Record: %s\n", txt_replies[i].txt));
+                                         &txt_replies);
+        test_ctx->error = (txt_replies == NULL) ? ENOENT : EOK;
+        for (txtptr = txt_replies; txtptr != NULL; txtptr = txtptr->next) {
+            DEBUG(2, ("TXT Record: %s\n", txtptr->txt));
         }
         break;
     case TESTING_SRV:
         recv_status = resolv_getsrv_recv(tmp_ctx, req, &status, NULL,
-                                         &srv_replies, &count);
-        test_ctx->error = (count == 0) ? ENOENT : EOK;
-        for (i = 0; i < count; i++) {
-            DEBUG(2, ("SRV Record: %d %d %d %s\n", srv_replies[i].weight,
-                      srv_replies[i].priority, srv_replies[i].port,
-                      srv_replies[i].host));
+                                         &srv_replies);
+        test_ctx->error = (srv_replies == NULL) ? ENOENT : EOK;
+        for (srvptr = srv_replies; srvptr != NULL; srvptr = srvptr->next) {
+            DEBUG(2, ("SRV Record: %d %d %d %s\n", srvptr->weight,
+                      srvptr->priority, srvptr->port,
+                      srvptr->host));
         }
         break;
     }
-- 
1.6.5.2

>From bc09339ff53de1b8cb54e356550ef9413db0f4e6 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhro...@redhat.com>
Date: Fri, 27 Nov 2009 09:39:41 +0100
Subject: [PATCH 2/3] Import ares 1.7.0 helpers

---
 server/Makefile.am                        |   11 ++-
 server/external/libcares.m4               |   21 +----
 server/resolv/ares/ares_data.c            |  140 +++++++++++++++++++++++++++++
 server/resolv/ares/ares_data.h            |   68 ++++++++++++++
 server/resolv/ares/ares_parse_srv_reply.c |   88 ++++++++++--------
 server/resolv/ares/ares_parse_srv_reply.h |   13 ++--
 server/resolv/ares/ares_parse_txt_reply.c |  119 +++++++++++++++++--------
 server/resolv/ares/ares_parse_txt_reply.h |    9 +-
 server/resolv/async_resolv.c              |   11 ++-
 server/resolv/async_resolv.h              |   10 +-
 10 files changed, 374 insertions(+), 116 deletions(-)
 create mode 100644 server/resolv/ares/ares_data.c
 create mode 100644 server/resolv/ares/ares_data.h

diff --git a/server/Makefile.am b/server/Makefile.am
index c43eb47..3902da1 100644
--- a/server/Makefile.am
+++ b/server/Makefile.am
@@ -209,11 +209,11 @@ SSSD_TOOLS_OBJ = \
 
 SSSD_RESOLV_OBJ = \
     resolv/async_resolv.c
-if BUILD_ARES_PARSE_SRV
-    SSSD_RESOLV_OBJ += resolv/ares/ares_parse_srv_reply.c
-endif
-if BUILD_ARES_PARSE_TXT
-    SSSD_RESOLV_OBJ += resolv/ares/ares_parse_txt_reply.c
+if BUILD_ARES_DATA
+    SSSD_RESOLV_OBJ += \
+	resolv/ares/ares_parse_srv_reply.c \
+	resolv/ares/ares_parse_txt_reply.c \
+	resolv/ares/ares_data.c
 endif
 
 SSSD_FAILOVER_OBJ = \
@@ -309,6 +309,7 @@ dist_noinst_HEADERS = \
     resolv/async_resolv.h \
     resolv/ares/ares_parse_srv_reply.h \
     resolv/ares/ares_parse_txt_reply.h \
+    resolv/ares/ares_data.h \
     tests/common.h
 
 
diff --git a/server/external/libcares.m4 b/server/external/libcares.m4
index 020a170..657deac 100644
--- a/server/external/libcares.m4
+++ b/server/external/libcares.m4
@@ -7,25 +7,14 @@ AC_CHECK_HEADERS(ares.h,
     [AC_MSG_ERROR([c-ares header files are not installed])]
 )
 
-dnl Check if this particular version of c-ares supports parsing of SRV records
+dnl Check if this particular version of c-ares supports the generic ares_free_data function
 AC_CHECK_LIB([cares],
-             [ares_parse_srv_reply],
-             [AC_DEFINE([HAVE_ARES_PARSE_SRV], 1, [Does c-ares support srv parsing?])
+             [ares_free_data],
+             [AC_DEFINE([HAVE_ARES_DATA], 1, [Does c-ares have ares_free_data()?])
              ],
              [
-                ares_build_srv=1
+                ares_data=1
              ]
 )
 
-dnl Check if this particular version of c-ares supports parsing of TXT records
-AC_CHECK_LIB([cares],
-             [ares_parse_txt_reply],
-             [AC_DEFINE([HAVE_ARES_PARSE_TXT], 1, [Does c-ares support txt parsing?])
-             ],
-             [
-                ares_build_txt=1
-             ]
-)
-
-AM_CONDITIONAL(BUILD_ARES_PARSE_SRV, test x$ares_build_srv = x1)
-AM_CONDITIONAL(BUILD_ARES_PARSE_TXT, test x$ares_build_txt = x1)
+AM_CONDITIONAL(BUILD_ARES_DATA, test x$ares_data = x1)
diff --git a/server/resolv/ares/ares_data.c b/server/resolv/ares/ares_data.c
new file mode 100644
index 0000000..1cccaa5
--- /dev/null
+++ b/server/resolv/ares/ares_data.c
@@ -0,0 +1,140 @@
+/* $Id: ares_data.c,v 1.2 2009-11-20 09:06:33 yangtse Exp $ */
+
+/* Copyright (C) 2009 by Daniel Stenberg
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in
+ * advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ */
+
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#include "ares.h"
+#include "ares_data.h"
+
+/*
+** ares_free_data() - c-ares external API function.
+**
+** This function must be used by the application to free data memory that
+** has been internally allocated by some c-ares function and for which a
+** pointer has already been returned to the calling application. The list
+** of c-ares functions returning pointers that must be free'ed using this
+** function is:
+**
+**   ares_parse_srv_reply()
+**   ares_parse_txt_reply()
+*/
+
+void _ares_free_data(void *dataptr)
+{
+  struct ares_data *ptr;
+
+  if (!dataptr)
+    return;
+
+  ptr = (void *)((char *)dataptr - offsetof(struct ares_data, data));
+
+  if (ptr->mark != ARES_DATATYPE_MARK)
+    return;
+
+  switch (ptr->type)
+    {
+      case ARES_DATATYPE_SRV_REPLY:
+
+        if (ptr->data.srv_reply.next)
+          _ares_free_data(ptr->data.srv_reply.next);
+        if (ptr->data.srv_reply.host)
+          free(ptr->data.srv_reply.host);
+        break;
+
+      case ARES_DATATYPE_TXT_REPLY:
+
+        if (ptr->data.txt_reply.next)
+          _ares_free_data(ptr->data.txt_reply.next);
+        if (ptr->data.txt_reply.txt)
+          free(ptr->data.txt_reply.txt);
+        break;
+
+      default:
+        return;
+    }
+
+  free(ptr);
+}
+
+
+/*
+** ares_malloc_data() - c-ares internal helper function.
+**
+** This function allocates memory for a c-ares private ares_data struct
+** for the specified ares_datatype, initializes c-ares private fields
+** and zero initializes those which later might be used from the public
+** API. It returns an interior pointer which can be passed by c-ares
+** functions to the calling application, and that must be free'ed using
+** c-ares external API function ares_free_data().
+*/
+
+void *_ares_malloc_data(ares_datatype type)
+{
+  struct ares_data *ptr;
+
+  ptr = malloc(sizeof(struct ares_data));
+  if (!ptr)
+    return NULL;
+
+  switch (type)
+    {
+      case ARES_DATATYPE_SRV_REPLY:
+        ptr->data.srv_reply.next = NULL;
+        ptr->data.srv_reply.host = NULL;
+        ptr->data.srv_reply.priority = 0;
+        ptr->data.srv_reply.weight = 0;
+        ptr->data.srv_reply.port = 0;
+        break;
+
+      case ARES_DATATYPE_TXT_REPLY:
+        ptr->data.txt_reply.next = NULL;
+        ptr->data.txt_reply.txt = NULL;
+        ptr->data.txt_reply.length  = 0;
+        break;
+
+      default:
+        free(ptr);
+        return NULL;
+    }
+
+  ptr->mark = ARES_DATATYPE_MARK;
+  ptr->type = type;
+
+  return &ptr->data;
+}
+
+
+/*
+** ares_get_datatype() - c-ares internal helper function.
+**
+** This function returns the ares_datatype of the data stored in a
+** private ares_data struct when given the public API pointer.
+*/
+
+ares_datatype ares_get_datatype(void * dataptr)
+{
+  struct ares_data *ptr;
+
+  ptr = (void *)((char *)dataptr - offsetof(struct ares_data, data));
+
+  if (ptr->mark == ARES_DATATYPE_MARK)
+    return ptr->type;
+
+  return ARES_DATATYPE_UNKNOWN;
+}
diff --git a/server/resolv/ares/ares_data.h b/server/resolv/ares/ares_data.h
new file mode 100644
index 0000000..d360631
--- /dev/null
+++ b/server/resolv/ares/ares_data.h
@@ -0,0 +1,68 @@
+/* $Id: ares_data.h,v 1.2 2009-11-23 12:03:33 yangtse Exp $ */
+
+/* Copyright (C) 2009 by Daniel Stenberg
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in
+ * advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ */
+
+#ifndef HAVE_ARES_DATA
+#include "resolv/ares/ares_parse_txt_reply.h"
+#include "resolv/ares/ares_parse_srv_reply.h"
+#endif /* HAVE_ARES_DATA */
+
+typedef enum {
+  ARES_DATATYPE_UNKNOWN = 1,  /* unknown data type     - introduced in 1.7.0 */
+  ARES_DATATYPE_SRV_REPLY,    /* struct ares_srv_reply - introduced in 1.7.0 */
+  ARES_DATATYPE_TXT_REPLY,    /* struct ares_txt_reply - introduced in 1.7.0 */
+#if 0
+  ARES_DATATYPE_ADDR6TTL,     /* struct ares_addrttl   */
+  ARES_DATATYPE_ADDRTTL,      /* struct ares_addr6ttl  */
+  ARES_DATATYPE_HOSTENT,      /* struct hostent        */
+  ARES_DATATYPE_OPTIONS,      /* struct ares_options   */
+#endif
+  ARES_DATATYPE_LAST          /* not used              - introduced in 1.7.0 */
+} ares_datatype;
+
+#define ARES_DATATYPE_MARK 0xbead
+
+/*
+ * ares_data struct definition is internal to c-ares and shall not
+ * be exposed by the public API in order to allow future changes
+ * and extensions to it without breaking ABI.  This will be used
+ * internally by c-ares as the container of multiple types of data
+ * dynamically allocated for which a reference will be returned
+ * to the calling application.
+ *
+ * c-ares API functions returning a pointer to c-ares internally
+ * allocated data will actually be returning an interior pointer
+ * into this ares_data struct.
+ *
+ * All this is 'invisible' to the calling application, the only
+ * requirement is that this kind of data must be free'ed by the
+ * calling application using ares_free_data() with the pointer
+ * it has received from a previous c-ares function call.
+ */
+
+struct ares_data {
+  ares_datatype type;  /* Actual data type identifier. */
+  unsigned int  mark;  /* Private ares_data signature. */
+  union {
+    struct ares_txt_reply txt_reply;
+    struct ares_srv_reply srv_reply;
+  } data;
+};
+
+void *_ares_malloc_data(ares_datatype type);
+void _ares_free_data(void *dataptr);
+
+ares_datatype ares_get_datatype(void * dataptr);
diff --git a/server/resolv/ares/ares_parse_srv_reply.c b/server/resolv/ares/ares_parse_srv_reply.c
index 9745fb0..086c4db 100644
--- a/server/resolv/ares/ares_parse_srv_reply.c
+++ b/server/resolv/ares/ares_parse_srv_reply.c
@@ -51,25 +51,24 @@
 #include "ares.h"
 /* this drags in some private macros c-ares uses */
 #include "ares_dns.h"
+#include "ares_data.h"
 
 #include "ares_parse_srv_reply.h"
 
 int _ares_parse_srv_reply (const unsigned char *abuf, int alen,
-                           struct srv_reply **srv_out, int *nsrvreply)
+                           struct ares_srv_reply **srv_out)
 {
-  unsigned int qdcount, ancount;
-  const unsigned char *aptr;
-  int status, i, rr_type, rr_class, rr_len;
+  unsigned int qdcount, ancount, i;
+  const unsigned char *aptr, *vptr;
+  int status, rr_type, rr_class, rr_len;
   long len;
   char *hostname = NULL, *rr_name = NULL;
-  struct srv_reply *srv = NULL;
+  struct ares_srv_reply *srv_head = NULL;
+  struct ares_srv_reply *srv_last = NULL;
+  struct ares_srv_reply *srv_curr;
 
   /* Set *srv_out to NULL for all failure cases. */
-  if (srv_out)
-    *srv_out = NULL;
-  /* Same with *nsrvreply. */
-  if (nsrvreply)
-    *nsrvreply = 0;
+  *srv_out = NULL;
 
   /* Give up if abuf doesn't have room for a header. */
   if (alen < HFIXEDSZ)
@@ -96,14 +95,6 @@ int _ares_parse_srv_reply (const unsigned char *abuf, int alen,
     }
   aptr += len + QFIXEDSZ;
 
-  /* Allocate srv_reply array; ancount gives an upper bound */
-  srv = malloc ((ancount) * sizeof (struct srv_reply));
-  if (!srv)
-    {
-      free (hostname);
-      return ARES_ENOMEM;
-    }
-
   /* Examine each answer resource record (RR) in turn. */
   for (i = 0; i < (int) ancount; i++)
     {
@@ -134,40 +125,59 @@ int _ares_parse_srv_reply (const unsigned char *abuf, int alen,
               break;
             }
 
-          srv[i].priority = ntohs (*((const uint16_t *)aptr));
-          aptr += sizeof(uint16_t);
-          srv[i].weight = ntohs (*((const uint16_t *)aptr));
-          aptr += sizeof(uint16_t);
-          srv[i].port = ntohs (*((const uint16_t *)aptr));
-          aptr += sizeof(uint16_t);
+          /* Allocate storage for this SRV answer appending it to the list */
+          srv_curr = _ares_malloc_data(ARES_DATATYPE_SRV_REPLY);
+          if (!srv_curr)
+            {
+              status = ARES_ENOMEM;
+              break;
+            }
+          if (srv_last)
+            {
+              srv_last->next = srv_curr;
+            }
+          else
+            {
+              srv_head = srv_curr;
+            }
+          srv_last = srv_curr;
+
+          vptr = aptr;
+          srv_curr->priority = ntohs (*((const unsigned short *)vptr));
+          vptr += sizeof(const unsigned short);
+          srv_curr->weight = ntohs (*((const unsigned short *)vptr));
+          vptr += sizeof(const unsigned short);
+          srv_curr->port = ntohs (*((const unsigned short *)vptr));
+          vptr += sizeof(const unsigned short);
 
-          status = ares_expand_name (aptr, abuf, alen, &srv[i].host, &len);
+          status = ares_expand_name (vptr, abuf, alen, &srv_curr->host, &len);
           if (status != ARES_SUCCESS)
             break;
+        }
 
-          /* Move on to the next record */
-          aptr += len;
+      /* Don't lose memory in the next iteration */
+      free(rr_name);
+      rr_name = NULL;
 
-          /* Don't lose memory in the next iteration */
-          free (rr_name);
-          rr_name = NULL;
-        }
+      /* Move on to the next record */
+      aptr += rr_len;
     }
 
+  if (hostname)
+    free (hostname);
+  if (rr_name)
+    free (rr_name);
+
   /* clean up on error */
   if (status != ARES_SUCCESS)
     {
-      free (srv);
-      free (hostname);
-      free (rr_name);
+      if (srv_head)
+        _ares_free_data (srv_head);
       return status;
     }
 
   /* everything looks fine, return the data */
-  *srv_out = srv;
-  *nsrvreply = ancount;
+  *srv_out = srv_head;
 
-  free (hostname);
-  free (rr_name);
-  return status;
+  return ARES_SUCCESS;
 }
diff --git a/server/resolv/ares/ares_parse_srv_reply.h b/server/resolv/ares/ares_parse_srv_reply.h
index caf93cd..29c6e08 100644
--- a/server/resolv/ares/ares_parse_srv_reply.h
+++ b/server/resolv/ares/ares_parse_srv_reply.h
@@ -21,14 +21,15 @@
 #ifndef __ARES_PARSE_SRV_REPLY_H__
 #define __ARES_PARSE_SRV_REPLY_H__
 
-struct srv_reply {
-    u_int16_t weight;
-    u_int16_t priority;
-    u_int16_t port;
-    char *host;
+struct ares_srv_reply {
+    struct ares_srv_reply  *next;
+    char                   *host;
+    unsigned short          priority;
+    unsigned short          weight;
+    unsigned short          port;
 };
 
 int _ares_parse_srv_reply (const unsigned char *abuf, int alen,
-                           struct srv_reply **srv_out, int *nsrvreply);
+                           struct ares_srv_reply **srv_out);
 
 #endif /* __ARES_PARSE_SRV_REPLY_H__ */
diff --git a/server/resolv/ares/ares_parse_txt_reply.c b/server/resolv/ares/ares_parse_txt_reply.c
index feb6af2..d710e8f 100644
--- a/server/resolv/ares/ares_parse_txt_reply.c
+++ b/server/resolv/ares/ares_parse_txt_reply.c
@@ -50,21 +50,26 @@
 #include "ares.h"
 /* this drags in some private macros c-ares uses */
 #include "ares_dns.h"
+#include "ares_data.h"
 
 #include "ares_parse_txt_reply.h"
 
-int _ares_parse_txt_reply(const unsigned char* abuf, int alen,
-                          struct txt_reply **txt_out, int *ntxtreply)
+int _ares_parse_txt_reply (const unsigned char *abuf, int alen,
+                           struct ares_txt_reply **txt_out)
 {
-  unsigned int qdcount, ancount;
+  size_t substr_len, str_len;
+  unsigned int qdcount, ancount, i;
   const unsigned char *aptr;
-  int status, i, rr_type, rr_class, rr_len;
+  const unsigned char *strptr;
+  int status, rr_type, rr_class, rr_len;
   long len;
   char *hostname = NULL, *rr_name = NULL;
-  struct txt_reply *txt = NULL;
+  struct ares_txt_reply *txt_head = NULL;
+  struct ares_txt_reply *txt_last = NULL;
+  struct ares_txt_reply *txt_curr;
 
-  if (txt_out)
-      *txt_out = NULL;
+  /* Set *txt_out to NULL for all failure cases. */
+  *txt_out = NULL;
 
   /* Give up if abuf doesn't have room for a header. */
   if (alen < HFIXEDSZ)
@@ -91,29 +96,21 @@ int _ares_parse_txt_reply(const unsigned char* abuf, int alen,
     }
   aptr += len + QFIXEDSZ;
 
-  /* Allocate txt_reply array; ancount gives an upper bound */
-  txt = malloc ((ancount) * sizeof (struct txt_reply));
-  if (!txt)
-    {
-      free (hostname);
-      return ARES_ENOMEM;
-    }
-
   /* Examine each answer resource record (RR) in turn. */
   for (i = 0; i < (int) ancount; i++)
     {
       /* Decode the RR up to the data field. */
       status = ares_expand_name(aptr, abuf, alen, &rr_name, &len);
       if (status != ARES_SUCCESS)
-	{
-	  break;
-	}
+       {
+         break;
+       }
       aptr += len;
       if (aptr + RRFIXEDSZ > abuf + alen)
-	{
-	  status = ARES_EBADRESP;
-	  break;
-	}
+       {
+         status = ARES_EBADRESP;
+         break;
+       }
       rr_type = DNS_RR_TYPE(aptr);
       rr_class = DNS_RR_CLASS(aptr);
       rr_len = DNS_RR_LEN(aptr);
@@ -121,37 +118,87 @@ int _ares_parse_txt_reply(const unsigned char* abuf, int alen,
 
       /* Check if we are really looking at a TXT record */
       if (rr_class == C_IN && rr_type == T_TXT)
-	{
-            /* Grab the TXT payload */
-            txt[i].length = rr_len;
-            txt[i].txt = malloc(sizeof(unsigned char) * rr_len);
-            if (txt[i].txt == NULL)
+        {
+          /* Allocate storage for this TXT answer appending it to the list */
+          txt_curr = _ares_malloc_data(ARES_DATATYPE_TXT_REPLY);
+          if (!txt_curr)
             {
                 status = ARES_ENOMEM;
                 break;
             }
-            memcpy((void *) txt[i].txt, aptr+1, sizeof(unsigned char) * rr_len);
-            /* Move on to the next record */
-            aptr += rr_len;
+          if (txt_last)
+            {
+              txt_last->next = txt_curr;
+            }
+          else
+            {
+              txt_head = txt_curr;
+            }
+          txt_last = txt_curr;
+
+          /*
+           * There may be multiple substrings in a single TXT record. Each
+           * substring may be up to 255 characters in length, with a
+           * "length byte" indicating the size of the substring payload.
+           * RDATA contains both the length-bytes and payloads of all
+           * substrings contained therein.
+           */
+
+          /* Compute total length to allow a single memory allocation */
+          strptr = aptr;
+          while (strptr < (aptr + rr_len))
+            {
+              substr_len = (unsigned char)*strptr;
+              txt_curr->length += substr_len;
+              strptr += substr_len + 1;
+            }
+
+          /* Including null byte */
+          txt_curr->txt = malloc (txt_curr->length + 1);
+          if (txt_curr->txt == NULL)
+            {
+              status = ARES_ENOMEM;
+              break;
+            }
+
+          /* Step through the list of substrings, concatenating them */
+          str_len = 0;
+          strptr = aptr;
+          while (strptr < (aptr + rr_len))
+            {
+              substr_len = (unsigned char)*strptr;
+              strptr++;
+              memcpy ((char *) txt_curr->txt + str_len, strptr, substr_len);
+              str_len += substr_len;
+              strptr += substr_len;
+            }
+          /* Make sure we NULL-terminate */
+          *((char *) txt_curr->txt + txt_curr->length) = '\0';
         }
 
       /* Don't lose memory in the next iteration */
       free(rr_name);
       rr_name = NULL;
+
+      /* Move on to the next record */
+      aptr += rr_len;
     }
 
-  free(hostname);
-  free(rr_name);
+  if (hostname)
+    free (hostname);
+  if (rr_name)
+    free (rr_name);
 
   /* clean up on error */
   if (status != ARES_SUCCESS)
     {
-      free (txt);
+      if (txt_head)
+        _ares_free_data (txt_head);
       return status;
     }
 
   /* everything looks fine, return the data */
-  *txt_out = txt;
-  *ntxtreply = ancount;
-  return 0;
+  *txt_out = txt_head;
+
+  return ARES_SUCCESS;
 }
diff --git a/server/resolv/ares/ares_parse_txt_reply.h b/server/resolv/ares/ares_parse_txt_reply.h
index 9fd4278..216e2c0 100644
--- a/server/resolv/ares/ares_parse_txt_reply.h
+++ b/server/resolv/ares/ares_parse_txt_reply.h
@@ -21,12 +21,13 @@
 #ifndef __ARES_PARSE_TXT_REPLY_H__
 #define __ARES_PARSE_TXT_REPLY_H__
 
-struct txt_reply {
-    int length;         /* length of the text */
-    unsigned char *txt; /* may contain nulls */
+struct ares_txt_reply {
+    struct ares_txt_reply  *next;
+    unsigned char          *txt;
+    size_t                  length;  /* length excludes null termination */
 };
 
 int _ares_parse_txt_reply(const unsigned char* abuf, int alen,
-                          struct txt_reply **txt_out, int *ntxtreply);
+                          struct ares_txt_reply **txt_out);
 
 #endif /* __ARES_PARSE_TXT_REPLY_H__ */
diff --git a/server/resolv/async_resolv.c b/server/resolv/async_resolv.c
index 51f981a..1bbdf17 100644
--- a/server/resolv/async_resolv.c
+++ b/server/resolv/async_resolv.c
@@ -42,15 +42,16 @@
 #include "util/dlinklist.h"
 #include "util/util.h"
 
-#ifndef HAVE_ARES_PARSE_SRV
+#ifndef HAVE_ARES_DATA
 #define ares_parse_srv_reply(abuf, alen, srv_out) \
     _ares_parse_srv_reply(abuf, alen, srv_out)
-#endif /* HAVE_ARES_PARSE_SRV */
-
-#ifndef HAVE_ARES_PARSE_TXT
 #define ares_parse_txt_reply(abuf, alen, txt_out) \
     _ares_parse_txt_reply(abuf, alen, txt_out)
-#endif /* HAVE_ARES_PARSE_TXT */
+#define ares_free_data(dataptr) \
+    _ares_free_data(dataptr)
+#define ares_malloc_data(data) \
+    _ares_malloc_data(data)
+#endif /* HAVE_ARES_DATA */
 
 struct fd_watch {
     struct fd_watch *prev;
diff --git a/server/resolv/async_resolv.h b/server/resolv/async_resolv.h
index 9d080ec..dab2fdf 100644
--- a/server/resolv/async_resolv.h
+++ b/server/resolv/async_resolv.h
@@ -29,13 +29,13 @@
 #include <netdb.h>
 #include <ares.h>
 
-#ifndef HAVE_ARES_PARSE_TXT
-#include "resolv/ares/ares_parse_txt_reply.h"
-#endif /* HAVE_ARES_PARSE_TXT */
+#include "config.h"
 
-#ifndef HAVE_ARES_PARSE_SRV
+#ifndef HAVE_ARES_DATA
 #include "resolv/ares/ares_parse_srv_reply.h"
-#endif /* HAVE_ARES_PARSE_SRV */
+#include "resolv/ares/ares_parse_txt_reply.h"
+#include "resolv/ares/ares_data.h"
+#endif /* HAVE_ARES_DATA */
 
 /*
  * An opaque structure which holds context for a module using the async
-- 
1.6.5.2

>From d2d677a1ff4f0212cfd956da4446b0e4f7db5905 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhro...@redhat.com>
Date: Mon, 7 Dec 2009 19:28:33 +0100
Subject: [PATCH 3/3] Don't build the SRV and TXT parsing code except for tests

---
 server/Makefile.am           |   20 ++++++++++++--------
 server/resolv/async_resolv.c |    6 ++++++
 2 files changed, 18 insertions(+), 8 deletions(-)

diff --git a/server/Makefile.am b/server/Makefile.am
index 3902da1..ed6f0de 100644
--- a/server/Makefile.am
+++ b/server/Makefile.am
@@ -209,12 +209,6 @@ SSSD_TOOLS_OBJ = \
 
 SSSD_RESOLV_OBJ = \
     resolv/async_resolv.c
-if BUILD_ARES_DATA
-    SSSD_RESOLV_OBJ += \
-	resolv/ares/ares_parse_srv_reply.c \
-	resolv/ares/ares_parse_txt_reply.c \
-	resolv/ares/ares_data.c
-endif
 
 SSSD_FAILOVER_OBJ = \
     providers/fail_over.c \
@@ -478,14 +472,24 @@ files_tests_CFLAGS = \
 files_tests_LDADD = \
     $(FILES_TESTS_LIBS)
 
+SSSD_RESOLV_TESTS_OBJ = \
+    $(SSSD_RESOLV_OBJ)
+if BUILD_ARES_DATA
+    SSSD_RESOLV_TESTS_OBJ += \
+	resolv/ares/ares_parse_srv_reply.c \
+	resolv/ares/ares_parse_txt_reply.c \
+	resolv/ares/ares_data.c
+endif
+
 resolv_tests_SOURCES = \
     tests/resolv-tests.c \
     tests/common.c \
     $(SSSD_UTIL_OBJ) \
-    $(SSSD_RESOLV_OBJ)
+    $(SSSD_RESOLV_TESTS_OBJ)
 resolv_tests_CFLAGS = \
     $(AM_CFLAGS) \
-    $(CHECK_CFLAGS)
+    $(CHECK_CFLAGS) \
+    -DBUILD_TXT_SRV
 resolv_tests_LDADD = \
     $(SSSD_LIBS) \
     $(CHECK_LIBS) \
diff --git a/server/resolv/async_resolv.c b/server/resolv/async_resolv.c
index 1bbdf17..2a06a62 100644
--- a/server/resolv/async_resolv.c
+++ b/server/resolv/async_resolv.c
@@ -442,6 +442,11 @@ ares_gethostbyname_wakeup(struct tevent_req *subreq)
                        state->family, resolv_gethostbyname_done, req);
 }
 
+/* SRV and TXT parsing is not used anywhere in the code yet, so we disable it
+ * for now
+ */
+#ifdef BUILD_TXT_SRV
+
 /*
  * A simple helper function that will take an array of struct ares_srv_reply that
  * was allocated by malloc() in c-ares and copies it using talloc. The old one
@@ -799,3 +804,4 @@ ares_gettxt_wakeup(struct tevent_req *subreq)
                ns_c_in, ns_t_txt, resolv_gettxt_done, req);
 }
 
+#endif
-- 
1.6.5.2

_______________________________________________
sssd-devel mailing list
sssd-devel@lists.fedorahosted.org
https://fedorahosted.org/mailman/listinfo/sssd-devel

Reply via email to