Hello, 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. > 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 > > --- > configure.ac | 2 +- > extras/tables/table-ldap/table_ldap.c | 105 ++++++++++++++++++-------- > 2 files changed, 73 insertions(+), 34 deletions(-) > > diff --git a/configure.ac b/configure.ac > index 14608b1..181a974 100644 > --- a/configure.ac > +++ b/configure.ac > @@ -297,7 +297,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" as discussed on irc this can be dropped. I've added AC_USE_SYSTEM_EXTENSIONS in configure.ac which is a tad better. We'll still need to add a compat for re{c,}allocarray, but i can handle it later. > ;; > *-*-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 3107d44..921935e 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; 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. > }; > > +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,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. > { > 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) > + *results = res; > goto end; > > error: > + for (i = 0; i < found; i++) { > + for (j = 0; j < n; j++) { > + aldap_free_attr(res[i].v[j]); > + } > + } > + free(res); > ret = -1; > > end: > @@ -465,9 +495,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 +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... separating the return value of ldap_query from the number of results would be useful here too. > + break; > + } > + if (strlcat(dst, res[j].v[0][i], sz) >= sz) { > + ret = -1; ditto > + 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 +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. > + if (res[j].v[i]) { > + aldap_free_attr(res[j].v[i]); > + } > + } > + } > [...] Thanks, Omar Polo