Hi

I have noticed, that table-ldap only use the last result of a query
result. So a alias query like

(&(objectclass=person)(memberof=cn=%s,cn=groups,dc=example,dc=com))

will only send mails to the last person in the response.

Also attached a patch to request only necesary attributes.

Philipp
From 471b7fcc13136a625b392e43f67ccd1f578ae218 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 772a1a5..3107d44 100644
--- a/extras/tables/table-ldap/table_ldap.c
+++ b/extras/tables/table-ldap/table_ldap.c
@@ -416,7 +416,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 8ece75b452b876bde50df806fb2a766b7b2c092b 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

---
 extras/tables/table-ldap/table_ldap.c | 94 ++++++++++++++++++---------
 1 file changed, 62 insertions(+), 32 deletions(-)

diff --git a/extras/tables/table-ldap/table_ldap.c b/extras/tables/table-ldap/table_ldap.c
index 3107d44..67f568d 100644
--- a/extras/tables/table-ldap/table_ldap.c
+++ b/extras/tables/table-ldap/table_ldap.c
@@ -63,6 +63,10 @@ struct query {
 	int	 attrn;
 };
 
+struct query_result {
+	char	**v[MAX_ATTRS];
+};
+
 static int ldap_run_query(int type, const char *, char *, size_t);
 
 static char *config, *url, *username, *password, *basedn, *ca_file;
@@ -397,12 +401,24 @@ 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 = realloc(*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)
 {
 	struct aldap_message		*m = NULL;
 	struct aldap_page_control	*pg = NULL;
-	int				 ret, found;
-	size_t				 i;
+	int				 ret;
+	size_t				 i, found = 0, numresults = 0;
 	char				 basedn__[MAX_LDAP_BASELEN];
 	char				 filter__[MAX_LDAP_FILTERLEN];
 	char				 key__[MAX_LDAP_IDENTIFIER];
@@ -413,12 +429,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;
+	ret = -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;
+			goto error;
 		}
 		if (pg != NULL) {
 			aldap_freepage(pg);
@@ -433,26 +448,32 @@ 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(results, &numresults)) {
+					goto error;
+				}
+			}
 			for (i = 0; i < n; ++i)
-				if (aldap_match_attr(m, attributes[i], &outp[i]) != 1)
+				if (aldap_match_attr(m, attributes[i], &(*results)[found].v[i]) != 1)
 					goto error;
 			aldap_freemsg(m);
 			m = NULL;
+			found++;
 		}
 	} while (pg != NULL);
 
-	ret = found;
+	if (found)
+		ret = found;
 	goto end;
 
 error:
+	free(*results);
 	ret = -1;
 
 end:
@@ -465,9 +486,10 @@ 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;
+	char			 filter[MAX_LDAP_FILTERLEN];
+	int			 ret, i, j;
 
 	switch (type) {
 	case K_ALIAS:		q = &queries[LDAP_ALIAS];	break;
@@ -495,39 +517,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;
+					break;
+				}
+				if (strlcat(dst, res[j].v[0][i], 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:
@@ -539,10 +562,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) {
+			if (res[j].v[i]) {
+				aldap_free_attr(res[j].v[i]);
+			}
+		}
+	}
+	free(res);
 
+	if (ret > 0)
+		ret = 1;
 	return ret;
 }
 
-- 
2.39.2

Reply via email to