Exim ldap lookup multiple DNs

Exim is one of the most flexible MTAs on the market. Its optional modules for database connectivity and its extensive config syntax allow full customization and use of external data sources. Provided LDAP backend allows three kinds of database query lookups:

ldap: This does an LDAP lookup using a query in the form of a URL, and returns attributes from a single entry. There is a variant called ldapm that permits values from multiple entries to be returned. A third variant called ldapdn returns the Distinguished Name of a single entry instead of any attribute values.

In some situations, it would be interesting to have a fourth query type: a lookup type that returned multiple DNs.

For instance, if your LDAP database also serves a DNS server with an ldap backend, your DNS subtree entries may look like this:

dc=mail, dc=example, dc=com, ou=domains, o=MyCompany, c=US

In this case, you could extract MX records from a list of DNs that match a particular filter like:

(&(objectClass=dNSDomain)(mXRecord=* $primary_hostname))

The complete query may look like this:

domainlist local_domains = @ : ${sg{${tr{${sg{${sg{${lookup ldapmdn { \
    ldap:///??sub?(&(objectClass=dNSDomain)(mXRecord=10 $primary_hostname))} { $value } \
    }}{,ou=domains,o=MyCompany,c=US}}}{}}}{dc=}{}}}{,}{.}}}{\n}{ : }}

To achieve this result, you need a small extension that enables a new query type called ldapmdn, whose syntax is similar to ldapdn but allows for multiple DNs. Here’s the patch for exim 4.69:

--- src/drtables.c.orig
+++ src/drtables.c
@@ -281,6 +281,23 @@
 #endif
   },

+/* LDAP lookup, allowing DN from more than one entry to be returned */
+
+  {
+  US"ldapmdn",                   /* lookup name */
+  lookup_querystyle,             /* query-style lookup */
+#ifdef LOOKUP_LDAP
+  eldap_open,       /* sic */    /* open function */
+  NULL,                          /* check function */
+  eldapmdn_find,                 /* find function */
+  NULL,                          /* no close function */
+  eldap_tidy,       /* sic */    /* tidy function */
+  eldap_quote       /* sic */    /* quoting function */
+#else
+  NULL, NULL, NULL, NULL, NULL, NULL /* lookup not present */
+#endif
+  },
+
 /* Linear search of single file */

   {
--- src/lookups/ldap.c.orig
+++ src/lookups/ldap.c
@@ -83,6 +83,7 @@
 #define SEARCH_LDAP_SINGLE 1         /* Get attributes from one entry only */
 #define SEARCH_LDAP_DN 2             /* Get just the DN from one entry */
 #define SEARCH_LDAP_AUTH 3           /* Just checking for authentication */
+#define SEARCH_LDAP_MULTIPLE_DN 4    /* Get just the DN from multiple entries */

 /* In all 4 cases, the DN is left in $ldap_dn (which post-dates the
 SEARCH_LDAP_DN lookup). */
@@ -185,6 +186,7 @@
     "sizelimit=%d timelimit=%d tcplimit=%d\n",
     (search_type == SEARCH_LDAP_MULTIPLE)? "m" :
     (search_type == SEARCH_LDAP_DN)? "dn" :
+    (search_type == SEARCH_LDAP_MULTIPLE_DN)? "mdn" :
     (search_type == SEARCH_LDAP_AUTH)? "auth" : "",
     ldap_url, server, s_port, sizelimit, timelimit, tcplimit);

@@ -577,7 +579,8 @@
     entries, the DNs will be concatenated, but we test for this case below, as
     for SEARCH_LDAP_SINGLE, and give an error. */

-    if (search_type == SEARCH_LDAP_DN)   /* Do not amalgamate these into one */
+    if (search_type == SEARCH_LDAP_DN ||
+      search_type == SEARCH_LDAP_MULTIPLE_DN) /* Do not amalgamate these into one */
       {                                  /* condition, because of the else */
       if (new_dn != NULL)                /* below, that's for the first only */
         {
@@ -820,7 +823,8 @@

 /* The search succeeded. Check if we have too many results */

-if (search_type != SEARCH_LDAP_MULTIPLE && rescount > 1)
+if (search_type != SEARCH_LDAP_MULTIPLE &&
+	search_type != SEARCH_LDAP_MULTIPLE_DN && rescount > 1)
   {
   *errmsg = string_sprintf("LDAP search: more than one entry (%d) was returned "
     "(filter not specific enough?)", rescount);
@@ -1126,6 +1130,14 @@
 return(control_ldap_search(ldap_url, SEARCH_LDAP_AUTH, result, errmsg));
 }

+int
+eldapmdn_find(void *handle, uschar *filename, uschar *ldap_url, int length,
+  uschar **result, uschar **errmsg, BOOL *do_cache)
+{
+/* Keep picky compilers happy */
+do_cache = do_cache;
+return(control_ldap_search(ldap_url, SEARCH_LDAP_MULTIPLE_DN, result, errmsg));
+}

 /*************************************************
--- src/lookups/ldap.h.orig
+++ src/lookups/ldap.h
@@ -16,6 +16,8 @@
                  uschar **, BOOL *);
 extern int     eldapm_find(void *, uschar *, uschar *, int, uschar **,
                  uschar **, BOOL *);
+extern int     eldapmdn_find(void *, uschar *, uschar *, int, uschar **,
+                 uschar **, BOOL *);
 extern void    eldap_tidy(void);
 extern uschar *eldap_quote(uschar *, uschar *);
This entry was posted in How-tos, Sysadmin and tagged , , , , . Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>