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