Hi

Thanks for your feedback. Updated patches are attached.

[2024-02-10 13:37] Omar Polo <o...@omarpolo.com>
> On 2024/02/06 13:43:09 +0100, Philipp <phil...@bureaucracy.de> wrote:
> > Hi
> > 
> > As discussed on irc, an updated version with reallocarray is attached.
> > 
> > Philipp
>
> A few comments on this now that I had some time to properly read it.
>
> The patch failed to apply cleanly on top of the latest master, so I had
> to manually apply some parts.

Not sure why, either because I have them on top of my ldaps patches or
because you forgott the "request only required attributes" patch. Because
I haven't change this one I haven't add it again. The atteched version is
direct on master and all patches are attached.

> > From 005b65c90f6017225c96b2769a6531057a337e70 Mon Sep 17 00:00:00 2001
> > From: Philipp Takacs <phil...@bureaucracy.de>
> > Date: Wed, 31 Jan 2024 17:50:52 +0100
> > Subject: [PATCH 2/5] table-ldap handle more then one result
> > 
> > ---
> [...]
> > @@ -63,6 +63,10 @@ struct query {
> >     int      attrn;
>
> Your diff has some int-vs-size_t comparisons, assignment etc.  One of
> such is caused by the `attrn' field of the struct query bing int.
>
> This seems to only be incremented, so converting it to a size_t should
> be fine and gets rids of a few headaches below, but see below.

I have changed this to size_t.

> > @@ -397,12 +401,25 @@ table_ldap_lookup(int service, struct dict *params, 
> > const char *key, char *dst,
> >  }
> >  
> >  static int
> > -ldap_query(const char *filter, const char *key, char **attributes, char 
> > ***outp, size_t n)
> > +realloc_results(struct query_result **r, size_t *num)
> > +{
> > +   struct query_result *new;
> > +   size_t newsize = MAX(1, (*num)*2);
> > +   if ((new = reallocarray(*r, newsize, sizeof(**r))) == NULL)
> > +           return 0;
> > +   *num = newsize;
> > +   *r = new;
> > +   return 1;
> > +}
> > +
> > +static int
> > +ldap_query(const char *filter, const char *key, char **attributes, struct 
> > query_result **results, size_t n)
>
> style nit: i'd prefer if the n argment was closer to attributes since
> it's the attribute length.

I have reorderd the arguments. Also changed the naming from 'n' to
'nattr'. This makes the code more readable.

> >  {
> >     struct aldap_message            *m = NULL;
> >     struct aldap_page_control       *pg = NULL;
> > -   int                              ret, found;
> > -   size_t                           i;
> > +   struct query_result             *res = NULL;
> > +   int                              ret;
> > +   size_t                           i, j, found = 0, numresults = 0;
> >     char                             basedn__[MAX_LDAP_BASELEN];
> >     char                             filter__[MAX_LDAP_FILTERLEN];
> >     char                             key__[MAX_LDAP_IDENTIFIER];
> > @@ -413,12 +430,11 @@ ldap_query(const char *filter, const char *key, char 
> > **attributes, char ***outp,
> >             return -1;
> >     if (strlcpy(key__, key, sizeof key__) >= sizeof key__)
> >             return -1;
> > -   found = -1;
> >     do {
> > -           if ((ret = aldap_search(aldap, basedn__, LDAP_SCOPE_SUBTREE,
> > -               filter__, key__, attributes, 0, 0, 0, pg)) == -1) {
> > -                   log_debug("ret=%d", ret);
> > -                   return -1;
> > +           ret = -1;
> > +           if (aldap_search(aldap, basedn__, LDAP_SCOPE_SUBTREE,
> > +               filter__, key__, attributes, 0, 0, 0, pg) == -1) {
> > +                   goto error;
> >             }
> >             if (pg != NULL) {
> >                     aldap_freepage(pg);
> > @@ -433,26 +449,40 @@ ldap_query(const char *filter, const char *key, char 
> > **attributes, char ***outp,
> >                                     pg = m->page;
> >                             aldap_freemsg(m);
> >                             m = NULL;
> > -                           if (found == -1)
> > -                                   found = 0;
> > +                           ret = 0;
> >                             break;
> >                     }
> >                     if (m->message_type != LDAP_RES_SEARCH_ENTRY)
> >                             goto error;
> >  
> > -                   found = 1;
> > +                   if (found >= numresults) {
> > +                           if (!realloc_results(&res, &numresults)) {
> > +                                   goto error;
> > +                           }
> > +                   }
> > +                   memset(&res[found], 0, sizeof(res[found]));
> >                     for (i = 0; i < n; ++i)
> > -                           if (aldap_match_attr(m, attributes[i], 
> > &outp[i]) != 1)
> > +                           if (aldap_match_attr(m, attributes[i], 
> > &res[found].v[i]) != 1)
> >                                     goto error;
> >                     aldap_freemsg(m);
> >                     m = NULL;
> > +                   found++;
> >             }
> >     } while (pg != NULL);
> >  
> > +   if (ret == -1)
> > +           goto error;
> >     ret = found;
>
> here we're setting an int to a size_t.  I doubt that in practice we can
> overflow, but I'd prefer this to be cleaner.
>
> one way could be converting everything to size_t and use an extra
> parameter to return the length.  This may help later in
> ldap_run_query(), see below.
>
> On the other hand, we could instead keep found, numresult etc as integer
> so we don't have the issue here. (and in that case, discard my previous
> suggestion of turning attrn to size_t)

I more like size_t way, so I have added a *numresults argument.

> > @@ -495,39 +526,40 @@ ldap_run_query(int type, const char *key, char *dst, 
> > size_t sz)
> >             return -1;
> >     }
> >  
> > -   memset(res, 0, sizeof(res));
> > -   ret = ldap_query(filter, key, q->attrs, res, q->attrn);
> > +   ret = ldap_query(filter, key, q->attrs, &res, q->attrn);
> >     if (ret <= 0 || dst == NULL)
> >             goto end;
> >  
> >     switch (type) {
> >  
> >     case K_ALIAS:
> > +   case K_MAILADDRMAP:
> >             memset(dst, 0, sz);
> > -           for (i = 0; res[0][i]; i++) {
> > -                   if (i && strlcat(dst, ", ", sz) >= sz) {
> > -                           ret = -1;
> > -                           break;
> > -                   }
> > -                   if (strlcat(dst, res[0][i], sz) >= sz) {
> > -                           ret = -1;
> > -                           break;
> > +           for (j = 0; j < ret; j++) {
> > +                   for (i = 0; res[j].v[0][i]; i++) {
> > +                           if ((i || j) && strlcat(dst, ", ", sz) >= sz) {
> > +                                   ret = -1;
>
> You're setting ret to -1 and exiting the inner loop, but the outer loop
> is still using ret...

And later the free also using it, fixed this.

> separating the return value of ldap_query from the number of results
> would be useful here too.

See above.

> [...]
> > @@ -539,10 +571,17 @@ ldap_run_query(int type, const char *key, char *dst, 
> > size_t sz)
> >             log_warnx("warn: could not format result");
> >  
> >  end:
> > -   for (i = 0; i < q->attrn; ++i)
> > -           if (res[i])
> > -                   aldap_free_attr(res[i]);
> > +   for (j = 0; j < ret; ++j) {
> > +           for (i = 0; i < q->attrn; ++i) {
>
> nit: it's a bit confusing that here i and j are used in the inverse
> order of the cleanup in ldap_query.

Yes, I was a bit lacy. Changed it consequently to i before j.

> [...]

I haven't tested this yet, I plan to test it on the weekend. 

Philipp
From 4ca89a68f09324bbc736173a3846c43c03772c8a Mon Sep 17 00:00:00 2001
From: Philipp Takacs <phil...@bureaucracy.de>
Date: Tue, 30 Jan 2024 17:07:07 +0100
Subject: [PATCH 1/2] table-ldap request only required attributes

---
 extras/tables/table-ldap/table_ldap.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/extras/tables/table-ldap/table_ldap.c b/extras/tables/table-ldap/table_ldap.c
index 64f99a8..bdd5d9c 100644
--- a/extras/tables/table-ldap/table_ldap.c
+++ b/extras/tables/table-ldap/table_ldap.c
@@ -366,7 +366,7 @@ ldap_query(const char *filter, const char *key, char **attributes, char ***outp,
 	found = -1;
 	do {
 		if ((ret = aldap_search(aldap, basedn__, LDAP_SCOPE_SUBTREE,
-		    filter__, key__, NULL, 0, 0, 0, pg)) == -1) {
+		    filter__, key__, attributes, 0, 0, 0, pg)) == -1) {
 			log_debug("ret=%d", ret);
 			return -1;
 		}
-- 
2.39.2

From 4bfe8ee070de3eec79c06e8c94b0d15aa90278b5 Mon Sep 17 00:00:00 2001
From: Philipp Takacs <phil...@bureaucracy.de>
Date: Wed, 31 Jan 2024 17:50:52 +0100
Subject: [PATCH 2/2] table-ldap handle more then one result

---
 configure.ac                          |   2 +-
 extras/tables/table-ldap/table_ldap.c | 124 +++++++++++++++++---------
 2 files changed, 81 insertions(+), 45 deletions(-)

diff --git a/configure.ac b/configure.ac
index 7ecc50d..1af7742 100644
--- a/configure.ac
+++ b/configure.ac
@@ -299,7 +299,7 @@ main() { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16))
 	;;
 *-*-linux* | *-gnu* | *-k*bsd*-gnu* )
 	use_pie=auto
-	CFLAGS="$CFLAGS -D_BSD_SOURCE"
+	CFLAGS="$CFLAGS -D_DEFAULT_SOURCE"
 	;;
 *-*-netbsd*)
 	if test "x$withval" != "xno" ; then
diff --git a/extras/tables/table-ldap/table_ldap.c b/extras/tables/table-ldap/table_ldap.c
index bdd5d9c..bf84dc6 100644
--- a/extras/tables/table-ldap/table_ldap.c
+++ b/extras/tables/table-ldap/table_ldap.c
@@ -59,7 +59,11 @@ enum {
 struct query {
 	char	*filter;
 	char	*attrs[MAX_ATTRS];
-	int	 attrn;
+	size_t	 attrn;
+};
+
+struct query_result {
+	char	**v[MAX_ATTRS];
 };
 
 static int ldap_run_query(int type, const char *, char *, size_t);
@@ -347,12 +351,26 @@ table_ldap_lookup(int service, struct dict *params, const char *key, char *dst,
 }
 
 static int
-ldap_query(const char *filter, const char *key, char **attributes, char ***outp, size_t n)
+realloc_results(struct query_result **r, size_t *num)
+{
+	struct query_result *new;
+	size_t newsize = MAX(1, (*num)*2);
+	if ((new = reallocarray(*r, newsize, sizeof(**r))) == NULL)
+		return 0;
+	*num = newsize;
+	*r = new;
+	return 1;
+}
+
+static int
+ldap_query(const char *filter, const char *key, char **attributes, size_t nattr,
+    struct query_result **results, size_t *nresults)
 {
 	struct aldap_message		*m = NULL;
 	struct aldap_page_control	*pg = NULL;
-	int				 ret, found;
-	size_t				 i;
+	struct query_result		*res = NULL;
+	int				 ret;
+	size_t				 i, j, found = 0, nres = 0;
 	char				 basedn__[MAX_LDAP_BASELEN];
 	char				 filter__[MAX_LDAP_FILTERLEN];
 	char				 key__[MAX_LDAP_IDENTIFIER];
@@ -363,12 +381,11 @@ ldap_query(const char *filter, const char *key, char **attributes, char ***outp,
 		return -1;
 	if (strlcpy(key__, key, sizeof key__) >= sizeof key__)
 		return -1;
-	found = -1;
 	do {
-		if ((ret = aldap_search(aldap, basedn__, LDAP_SCOPE_SUBTREE,
-		    filter__, key__, attributes, 0, 0, 0, pg)) == -1) {
-			log_debug("ret=%d", ret);
-			return -1;
+		ret = -1;
+		if (aldap_search(aldap, basedn__, LDAP_SCOPE_SUBTREE,
+		    filter__, key__, attributes, 0, 0, 0, pg) == -1) {
+			goto end;
 		}
 		if (pg != NULL) {
 			aldap_freepage(pg);
@@ -377,35 +394,46 @@ ldap_query(const char *filter, const char *key, char **attributes, char ***outp,
 
 		while ((m = aldap_parse(aldap)) != NULL) {
 			if (aldap->msgid != m->msgid)
-				goto error;
+				goto end;
 			if (m->message_type == LDAP_RES_SEARCH_RESULT) {
 				if (m->page != NULL && m->page->cookie_len)
 					pg = m->page;
 				aldap_freemsg(m);
 				m = NULL;
-				if (found == -1)
-					found = 0;
+				ret = 0;
 				break;
 			}
 			if (m->message_type != LDAP_RES_SEARCH_ENTRY)
-				goto error;
+				goto end;
 
-			found = 1;
-			for (i = 0; i < n; ++i)
-				if (aldap_match_attr(m, attributes[i], &outp[i]) != 1)
-					goto error;
+			if (found >= nres) {
+				if (!realloc_results(&res, &nres)) {
+					goto end;
+				}
+			}
+			memset(&res[found], 0, sizeof(res[found]));
+			for (i = 0; i < nattr; ++i)
+				if (aldap_match_attr(m, attributes[i], &res[found].v[i]) != 1)
+					goto end;
 			aldap_freemsg(m);
 			m = NULL;
+			found++;
 		}
 	} while (pg != NULL);
 
-	ret = found;
-	goto end;
-
-error:
-	ret = -1;
-
 end:
+	if (ret == -1) {
+		for (i = 0; i < found; i++) {
+			for (j = 0; j < nattr; j++) {
+				aldap_free_attr(res[i].v[j]);
+			}
+		}
+		free(res);
+	} else {
+		ret = found ? 1 : 0;
+		*nresults = found;
+		*results = res;
+	}
 	if (m)
 		aldap_freemsg(m);
 	log_debug("debug: table_ldap: ldap_query: filter=%s, ret=%d", filter, ret);
@@ -415,9 +443,11 @@ end:
 static int
 ldap_run_query(int type, const char *key, char *dst, size_t sz)
 {
-	struct query	 *q;
-	char		**res[4], filter[MAX_LDAP_FILTERLEN];
-	int		  ret, i;
+	struct query		*q;
+	struct query_result	*res = NULL;
+	size_t			 i, j, nres = 0;
+	char			 filter[MAX_LDAP_FILTERLEN];
+	int			 ret;
 
 	switch (type) {
 	case K_ALIAS:		q = &queries[LDAP_ALIAS];	break;
@@ -445,39 +475,40 @@ ldap_run_query(int type, const char *key, char *dst, size_t sz)
 		return -1;
 	}
 
-	memset(res, 0, sizeof(res));
-	ret = ldap_query(filter, key, q->attrs, res, q->attrn);
+	ret = ldap_query(filter, key, q->attrs, q->attrn, &res, &nres);
 	if (ret <= 0 || dst == NULL)
 		goto end;
 
 	switch (type) {
 
 	case K_ALIAS:
+	case K_MAILADDRMAP:
 		memset(dst, 0, sz);
-		for (i = 0; res[0][i]; i++) {
-			if (i && strlcat(dst, ", ", sz) >= sz) {
-				ret = -1;
-				break;
-			}
-			if (strlcat(dst, res[0][i], sz) >= sz) {
-				ret = -1;
-				break;
+		for (i = 0; ret == 1 && i < nres; i++) {
+			for (j = 0; ret == 1 && res[i].v[0][j]; j++) {
+				if ((i || j) && strlcat(dst, ", ", sz) >= sz) {
+					ret = -1;
+					break;
+				}
+				if (strlcat(dst, res[i].v[0][j], sz) >= sz) {
+					ret = -1;
+					break;
+				}
 			}
 		}
 		break;
 	case K_DOMAIN:
 	case K_MAILADDR:
-	case K_MAILADDRMAP:
-		if (strlcpy(dst, res[0][0], sz) >= sz)
+		if (strlcpy(dst, res[0].v[0][0], sz) >= sz)
 			ret = -1;
 		break;
 	case K_CREDENTIALS:
-		if (snprintf(dst, sz, "%s:%s", res[0][0], res[1][0]) >= (int)sz)
+		if (snprintf(dst, sz, "%s:%s", res[0].v[0][0], res[0].v[1][0]) >= (int)sz)
 			ret = -1;
 		break;
 	case K_USERINFO:
-		if (snprintf(dst, sz, "%s:%s:%s", res[0][0], res[1][0],
-		    res[2][0]) >= (int)sz)
+		if (snprintf(dst, sz, "%s:%s:%s", res[0].v[0][0], res[0].v[1][0],
+		    res[0].v[2][0]) >= (int)sz)
 			ret = -1;
 		break;
 	default:
@@ -489,9 +520,14 @@ ldap_run_query(int type, const char *key, char *dst, size_t sz)
 		log_warnx("warn: could not format result");
 
 end:
-	for (i = 0; i < q->attrn; ++i)
-		if (res[i])
-			aldap_free_attr(res[i]);
+	for (i = 0; i < nres; ++j) {
+		for (j = 0; j < q->attrn; ++i) {
+			if (res[i].v[j]) {
+				aldap_free_attr(res[i].v[j]);
+			}
+		}
+	}
+	free(res);
 
 	return ret;
 }
-- 
2.39.2

Reply via email to