cf/README for sendmail 8.12.3

Eric Allman of the Sendmail Consortium

Using LDAP For Aliases, Maps, And Classes

  1. Aliases
  2. Maps
  3. Classes

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 below show 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. Feedback via sendmail@sendmail.org is encouraged.

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

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., mailertable, 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_dbaccess
authinfoauthinfo
bitdomainbitdomain
domaintabledomain
genericstablegenerics
mailertablemailer
uucpdomainuucpdomain
virtusertablevirtuser

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

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

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:

CommandsendmailMTAClassName
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.