LDAP can be used for aliases, maps, and classes by either specifying your own LDAP map specification or using the built-in default LDAP map specification. The built-in default specifications all provide lookups which match against either the machine's fully qualified hostname (${j}) or a "cluster". The cluster allows you to share LDAP entries among a large number of machines without having to enter each of the machine names into each LDAP entry. To set the LDAP cluster name to use for a particular machine or set of machines, set the confLDAP_CLUSTER m4 variable to a unique name. For example:
define(`confLDAP_CLUSTER', `Servers')
Here, the word `Servers' will be the cluster name. As an example, assume that smtp.sendmail.org, etrn.sendmail.org, and mx.sendmail.org all belong to the Servers cluster.
Some of the LDAP LDIF examples shown below will make use of the Servers cluster. Every entry must have either a sendmailMTAHost or sendmailMTACluster attribute or it will be ignored. Be careful as mixing clusters and individual host records can have surprising results (see the CAUTION sections below).
See the file cf/sendmail.schema for the actual LDAP schemas. Note that this schema (and therefore the lookups and examples below) is experimental at this point as it has had little public review. Therefore, it may change in future versions. Sending feedback via sendmail-YYYY@support.sendmail.org is encouraged (replace YYYY with the current year, e.g., 2005).
Aliases
The ALIAS_FILE (O AliasFile) option can be set to use LDAP for alias lookups. To use the default schema, simply use:
define(`ALIAS_FILE', `ldap:')
By doing so, you will use the default schema which expands to a map declared as follows:
ldap -k (&(objectClass=sendmailMTAAliasObject)
(sendmailMTAAliasGrouping=aliases)
(|(sendmailMTACluster=${sendmailMTACluster})
(sendmailMTAHost=$j))
(sendmailMTAKey=%0))
-v sendmailMTAAliasValue,sendmailMTAAliasSearch:FILTER:sendmailMTAAliasObject,sendmailMTAAliasURL:URL:sendmailMTAAliasObject
NOTE: The macros shown above ${sendmailMTACluster} and $j are not actually used when the binary expands the `ldap:' token as the AliasFile option is not actually macro-expanded when read from the sendmail.cf file.
Example LDAP LDIF entries might be:
dn: sendmailMTAKey=sendmail-list, dc=sendmail, dc=org
objectClass: sendmailMTA
objectClass: sendmailMTAAlias
objectClass: sendmailMTAAliasObject
sendmailMTAAliasGrouping: aliases
sendmailMTAHost: etrn.sendmail.org
sendmailMTAKey: sendmail-list
sendmailMTAAliasValue: ca@example.org
sendmailMTAAliasValue: eric
sendmailMTAAliasValue: gshapiro@example.com
dn: sendmailMTAKey=owner-sendmail-list, dc=sendmail, dc=org
objectClass: sendmailMTA
objectClass: sendmailMTAAlias
objectClass: sendmailMTAAliasObject
sendmailMTAAliasGrouping: aliases
sendmailMTAHost: etrn.sendmail.org
sendmailMTAKey: owner-sendmail-list
sendmailMTAAliasValue: eric
dn: sendmailMTAKey=postmaster, dc=sendmail, dc=org
objectClass: sendmailMTA
objectClass: sendmailMTAAlias
objectClass: sendmailMTAAliasObject
sendmailMTAAliasGrouping: aliases
sendmailMTACluster: Servers
sendmailMTAKey: postmaster
sendmailMTAAliasValue: eric
Here, the aliases sendmail-list and owner-sendmail-list will be available only on etrn.sendmail.org but the postmaster alias will be available on every machine in the Servers cluster (including etrn.sendmail.org).
CAUTION: aliases are additive so that entries like these:
dn: sendmailMTAKey=bob, dc=sendmail, dc=org
objectClass: sendmailMTA
objectClass: sendmailMTAAlias
objectClass: sendmailMTAAliasObject
sendmailMTAAliasGrouping: aliases
sendmailMTACluster: Servers
sendmailMTAKey: bob
sendmailMTAAliasValue: eric
dn: sendmailMTAKey=bobetrn, dc=sendmail, dc=org
objectClass: sendmailMTA
objectClass: sendmailMTAAlias
objectClass: sendmailMTAAliasObject
sendmailMTAAliasGrouping: aliases
sendmailMTAHost: etrn.sendmail.org
sendmailMTAKey: bob
sendmailMTAAliasValue: gshapiro
would mean that on all of the hosts in the cluster, mail to bob would go to eric EXCEPT on etrn.sendmail.org in which case it would go to BOTH eric and gshapiro.
If you prefer not to use the default LDAP schema for your aliases, you can specify the map parameters when setting ALIAS_FILE. For example:
define(`ALIAS_FILE', `ldap:-k (&(objectClass=mailGroup)(mail=%0)) -v mgrpRFC822MailMember')
Maps
FEATURE()'s which take an optional map definition argument (e.g., access, mailertable, virtusertable, etc.) can instead take the special keyword `LDAP', e.g.:
FEATURE(`access_db', `LDAP')
FEATURE(`virtusertable', `LDAP')
When this keyword is given, that map will use LDAP lookups consisting of the objectClass sendmailMTAClassObject, the attribute sendmailMTAMapName with the map name, a search attribute of sendmailMTAKey, and the value attribute sendmailMTAMapValue.
The values for sendmailMTAMapName are: FEATURE() sendmailMTAMapName --------- ------------------ access_db access authinfo authinfo bitdomain bitdomain domaintable domain genericstable generics mailertable mailer uucpdomain uucpdomain virtusertable virtuser
For example, FEATURE(`mailertable', `LDAP') would use the map definition:
Kmailertable ldap -k (&(objectClass=sendmailMTAMapObject)
(sendmailMTAMapName=mailer)
(|(sendmailMTACluster=${sendmailMTACluster})
(sendmailMTAHost=$j))
(sendmailMTAKey=%0))
-1 -v sendmailMTAMapValue,sendmailMTAMapSearch:FILTER:sendmailMTAMapObject,sendmailMTAMapURL:URL:sendmailMTAMapObject
An example LDAP LDIF entry using this map might be:
dn: sendmailMTAMapName=mailer, dc=sendmail, dc=org
objectClass: sendmailMTA
objectClass: sendmailMTAMap
sendmailMTACluster: Servers
sendmailMTAMapName: mailer
dn: sendmailMTAKey=example.com, sendmailMTAMapName=mailer, dc=sendmail, dc=org
objectClass: sendmailMTA
objectClass: sendmailMTAMap
objectClass: sendmailMTAMapObject
sendmailMTAMapName: mailer
sendmailMTACluster: Servers
sendmailMTAKey: example.com
sendmailMTAMapValue: relay:[smtp.example.com]
CAUTION: If your LDAP database contains the record above and *ALSO* a host specific record such as:
dn: sendmailMTAKey=example.com@etrn, sendmailMTAMapName=mailer, dc=sendmail, dc=org
objectClass: sendmailMTA
objectClass: sendmailMTAMap
objectClass: sendmailMTAMapObject
sendmailMTAMapName: mailer
sendmailMTAHost: etrn.sendmail.org
sendmailMTAKey: example.com
sendmailMTAMapValue: relay:[mx.example.com]
then these entries will give unexpected results. When the lookup is done on etrn.sendmail.org, the effect is that there is *NO* match at all as maps require a single match. Since the host etrn.sendmail.org is also in the Servers cluster, LDAP would return two answers for the example.com map key in which case sendmail would treat this as no match at all.
If you prefer not to use the default LDAP schema for your maps, you can specify the map parameters when using the FEATURE(). For example:
FEATURE(`access_db', `ldap:-1 -k (&(objectClass=mapDatabase)(key=%0)) -v value')
Classes
Normally, classes can be filled via files or programs. As of 8.12, they can also be filled via map lookups using a new syntax:
F{ClassName}mapkey@mapclass:mapspec
mapkey is optional and if not provided the map key will be empty. This can be used with LDAP to read classes from LDAP. Note that the lookup is only done when sendmail is initially started. Use the special value `@LDAP' to use the default LDAP schema. For example:
RELAY_DOMAIN_FILE(`@LDAP')
would put all of the attribute sendmailMTAClassValue values of LDAP records with objectClass sendmailMTAClass and an attribute sendmailMTAClassName of 'R' into class $={R}. In other words, it is equivalent to the LDAP map specification:
F{R}@ldap:-k (&(objectClass=sendmailMTAClass)
(sendmailMTAClassName=R)
(|(sendmailMTACluster=${sendmailMTACluster})
(sendmailMTAHost=$j)))
-v sendmailMTAClassValue,sendmailMTAClassSearch:FILTER:sendmailMTAClass,sendmailMTAClassURL:URL:sendmailMTAClass
NOTE: The macros shown above ${sendmailMTACluster} and $j are not actually used when the binary expands the `@LDAP' token as class declarations are not actually macro-expanded when read from the sendmail.cf file.
This can be used with class related commands such as RELAY_DOMAIN_FILE(), MASQUERADE_DOMAIN_FILE(), etc:
Command sendmailMTAClassName ------- -------------------- CANONIFY_DOMAIN_FILE() Canonify EXPOSED_USER_FILE() E GENERICS_DOMAIN_FILE() G LDAPROUTE_DOMAIN_FILE() LDAPRoute LDAPROUTE_EQUIVALENT_FILE() LDAPRouteEquiv LOCAL_USER_FILE() L MASQUERADE_DOMAIN_FILE() M MASQUERADE_EXCEPTION_FILE() N RELAY_DOMAIN_FILE() R VIRTUSER_DOMAIN_FILE() VirtHost
You can also add your own as any 'F'ile class of the form:
F{ClassName}@LDAP
^^^^^^^^^
will use "ClassName" for the sendmailMTAClassName.
An example LDAP LDIF entry would look like:
dn: sendmailMTAClassName=R, dc=sendmail, dc=org
objectClass: sendmailMTA
objectClass: sendmailMTAClass
sendmailMTACluster: Servers
sendmailMTAClassName: R
sendmailMTAClassValue: sendmail.org
sendmailMTAClassValue: example.com
sendmailMTAClassValue: 10.56.23
CAUTION: If your LDAP database contains the record above and *ALSO* a host specific record such as:
dn: sendmailMTAClassName=R@etrn.sendmail.org, dc=sendmail, dc=org
objectClass: sendmailMTA
objectClass: sendmailMTAClass
sendmailMTAHost: etrn.sendmail.org
sendmailMTAClassName: R
sendmailMTAClassValue: example.com
the result will be similar to the aliases caution above. When the lookup is done on etrn.sendmail.org, $={R} would contain all of the entries (from both the cluster match and the host match). In other words, the effective is additive.
If you prefer not to use the default LDAP schema for your classes, you can specify the map parameters when using the class command. For example:
VIRTUSER_DOMAIN_FILE(`@ldap:-k (&(objectClass=virtHosts)(host=*)) -v host')
Remember, macros can not be used in a class declaration as the binary does not expand them.
LDAP ROUTING
FEATURE(`ldap_routing') can be used to implement the IETF Internet Draft LDAP Schema for Intranet Mail Routing (draft-lachman-laser-ldap-mail-routing-01). This feature enables LDAP-based rerouting of a particular address to either a different host or a different address. The LDAP lookup is first attempted on the full address (e.g., user@example.com) and then on the domain portion (e.g., @example.com). Be sure to setup your domain for LDAP routing using LDAPROUTE_DOMAIN(), e.g.:
LDAPROUTE_DOMAIN(`example.com')
Additionally, you can specify equivalent domains for LDAP routing using LDAPROUTE_EQUIVALENT() and LDAPROUTE_EQUIVALENT_FILE(). 'Equivalent' hostnames are mapped to $M (the masqueraded hostname for the server) before the LDAP query. For example, if the mail is addressed to user@host1.example.com, normally the LDAP lookup would only be done for 'user@host1.example.com' and '@host1.example.com'. However, if LDAPROUTE_EQUIVALENT(`host1.example.com') is used, the lookups would also be done on 'user@example.com' and '@example.com' after attempting the host1.example.com lookups.
By default, the feature will use the schemas as specified in the draft and will not reject addresses not found by the LDAP lookup. However, this behavior can be changed by giving additional arguments to the FEATURE() command:
FEATURE(`ldap_routing', <mailHost>, <mailRoutingAddress>, <bounce>,
<detail>, <nodomain>, <tempfail>)
where <mailHost> is a map definition describing how to lookup an alternative mail host for a particular address;
<mailRoutingAddress> is a map definition describing how to lookup an alternative address for a particular address;
the <bounce> argument, if present and not the word "passthru", dictates that mail should be bounced if neither a mailHost nor mailRoutingAddress is found, if set to "sendertoo", the sender will be rejected if not found in LDAP;
and <detail> indicates what actions to take if the address contains +detail information -- `strip' tries the lookup with the +detail and if no matches are found, strips the +detail and tries the lookup again; `preserve', does the same as `strip' but if a mailRoutingAddress match is found, the +detail information is copied to the new address;
the <nodomain> argument, if present, will prevent the @domain lookup if the full address is not found in LDAP;
the <tempfail> argument, if set to "tempfail", instructs the rules to give an SMTP 4XX temporary error if the LDAP server gives the MTA a temporary failure, or if set to "queue" (the default), the MTA will locally queue the mail.
The default <mailHost> map definition is:
ldap -1 -T<TMPF> -v mailHost -k (&(objectClass=inetLocalMailRecipient)
(mailLocalAddress=%0))
The default <mailRoutingAddress> map definition is:
ldap -1 -T<TMPF> -v mailRoutingAddress
-k (&(objectClass=inetLocalMailRecipient)
(mailLocalAddress=%0))
Note that neither includes the LDAP server hostname (-h server) or base DN (-b o=org,c=COUNTRY), both necessary for LDAP queries. It is presumed that your .mc file contains a setting for the confLDAP_DEFAULT_SPEC option with these settings. If this is not the case, the map definitions should be changed as described above. The "-T<TMPF>" is required in any user specified map definition to catch temporary errors.
The following possibilities exist as a result of an LDAP lookup on an address:
mailHost is mailRoutingAddress is Results in ----------- --------------------- ---------- set to a set mail delivered to "local" host mailRoutingAddress set to a not set delivered to "local" host original address set to a set mailRoutingAddress remote host relayed to mailHost set to a not set original address remote host relayed to mailHost not set set mail delivered to mailRoutingAddress not set not set delivered to original address *OR* bounced as unknown user
The term "local" host above means the host specified is in class {w}. If the result would mean sending the mail to a different host, that host is looked up in the mailertable before delivery.
Note that the last case depends on whether the third argument is given to the FEATURE() command. The default is to deliver the message to the original address.
The LDAP entries should be set up with an objectClass of inetLocalMailRecipient and the address be listed in a mailLocalAddress attribute. If present, there must be only one mailHost attribute and it must contain a fully qualified host name as its value. Similarly, if present, there must be only one mailRoutingAddress attribute and it must contain an RFC 822 compliant address. Some example LDAP records (in LDIF format):
dn: uid=tom, o=example.com, c=US
objectClass: inetLocalMailRecipient
mailLocalAddress: tom@example.com
mailRoutingAddress: thomas@mailhost.example.com
This would deliver mail for tom@example.com to thomas@mailhost.example.com.
dn: uid=dick, o=example.com, c=US
objectClass: inetLocalMailRecipient
mailLocalAddress: dick@example.com
mailHost: eng.example.com
This would relay mail for dick@example.com to the same address but redirect the mail to MX records listed for the host eng.example.com (unless the mailertable overrides).
dn: uid=harry, o=example.com, c=US
objectClass: inetLocalMailRecipient
mailLocalAddress: harry@example.com
mailHost: mktmail.example.com
mailRoutingAddress: harry@mkt.example.com
This would relay mail for harry@example.com to the MX records listed for the host mktmail.example.com using the new address harry@mkt.example.com when talking to that host.
dn: uid=virtual.example.com, o=example.com, c=US
objectClass: inetLocalMailRecipient
mailLocalAddress: @virtual.example.com
mailHost: server.example.com
mailRoutingAddress: virtual@example.com
This would send all mail destined for any username @virtual.example.com to the machine server.example.com's MX servers and deliver to the address virtual@example.com on that relay machine.
LDAP Recursion
LDAP Recursion allows you to add types to the search attributes on an LDAP map specification. The syntax is:
-v ATTRIBUTE[:TYPE[:OBJECTCLASS[|OBJECTCLASS|...]]]
The new TYPEs are:
NORMAL - This attribute type specifies the attribute to add to the results string. This is the default.
DN - Any matches for this attribute are expected to have a value of a fully qualified distinguished name. Sendmail will lookup that DN and apply the attributes requested to the returned DN record.
FILTER - Any matches for this attribute are expected to have a value of an LDAP search filter. Sendmail will perform a lookup with the same parameters as the original search but replaces the search filter with the one specified here.
URL - Any matches for this attribute are expected to have a value of an LDAP URL. Sendmail will perform a lookup of that URL and use the results from the attributes named in that URL. Note however that the search is done using the current LDAP connection, regardless of what is specified as the scheme, LDAP host, and LDAP port in the LDAP URL.
Any untyped attributes are considered NORMAL attributes as described above.
The optional OBJECTCLASS (| separated) list contains the objectClass values for which that attribute applies. If the list is given, the attribute named will only be used if the LDAP record being returned is a member of that object class. Note that if these new value attribute TYPEs are used in an AliasFile option setting, it will need to be double quoted to prevent sendmail from misparsing the colons.
Note that LDAP recursion attributes which do not ultimately point to an LDAP record are not considered an error.
Example
Since examples usually help clarify, here is an example which uses all four of the new types:
O LDAPDefaultSpec=-h ldap.example.com -b dc=example,dc=com
Kexample ldap
-z,
-k (&(objectClass=sendmailMTAAliasObject)(sendmailMTAKey=%0))
-v sendmailMTAAliasValue,mail:NORMAL:inetOrgPerson,
uniqueMember:DN:groupOfUniqueNames,
sendmailMTAAliasSearch:FILTER:sendmailMTAAliasObject,
sendmailMTAAliasURL:URL:sendmailMTAAliasObject
That definition specifies that:
Any value in a sendmailMTAAliasValue attribute will be added to the result string regardless of object class.
The mail attribute will be added to the result string if the LDAP record is a member of the inetOrgPerson object class.
The uniqueMember attribute is a recursive attribute, used only in groupOfUniqueNames records, and should contain an LDAP DN pointing to another LDAP record. The desire here is to return the mail attribute from those DNs.
The sendmailMTAAliasSearch attribute and sendmailMTAAliasURL are both used only if referenced in a sendmailMTAAliasObject. They are both recursive, the first for a new LDAP search string and the latter for an LDAP URL.
Next Section: DNS and Sendmail - 29 of 32