diff options
Diffstat (limited to '')
-rw-r--r-- | README_FILES/LDAP_README | 465 |
1 files changed, 465 insertions, 0 deletions
diff --git a/README_FILES/LDAP_README b/README_FILES/LDAP_README new file mode 100644 index 0000000..eeef565 --- /dev/null +++ b/README_FILES/LDAP_README @@ -0,0 +1,465 @@ +PPoossttffiixx LLDDAAPP HHoowwttoo + +------------------------------------------------------------------------------- + +LLDDAAPP SSuuppppoorrtt iinn PPoossttffiixx + +Postfix can use an LDAP directory as a source for any of its lookups: aliases +(5), virtual(5), canonical(5), etc. This allows you to keep information for +your mail service in a replicated network database with fine-grained access +controls. By not storing it locally on the mail server, the administrators can +maintain it from anywhere, and the users can control whatever bits of it you +think appropriate. You can have multiple mail servers using the same +information, without the hassle and delay of having to copy it to each. + +Topics covered in this document: + + * Building Postfix with LDAP support + * Configuring LDAP lookups + * Example: aliases + * Example: virtual domains/addresses + * Example: expanding LDAP groups + * Other uses of LDAP lookups + * Notes and things to think about + * Feedback + * Credits + +BBuuiillddiinngg PPoossttffiixx wwiitthh LLDDAAPP ssuuppppoorrtt + +These instructions assume that you build Postfix from source code as described +in the INSTALL document. Some modification may be required if you build Postfix +from a vendor-specific source package. + +Note 1: Postfix no longer supports the LDAP version 1 interface. + +Note 2: to use LDAP with Debian GNU/Linux's Postfix, all you need is to install +the postfix-ldap package and you're done. There is no need to recompile +Postfix. + +You need to have LDAP libraries and include files installed somewhere on your +system, and you need to configure the Postfix Makefiles accordingly. + +For example, to build the OpenLDAP libraries for use with Postfix (i.e. LDAP +client code only), you could use the following command: + + % ./configure --without-kerberos --without-cyrus-sasl --without-tls \ + --without-threads --disable-slapd --disable-slurpd \ + --disable-debug --disable-shared + +If you're using the libraries from the UM distribution (http://www.umich.edu/ +~dirsvcs/ldap/ldap.html) or OpenLDAP (http://www.openldap.org), something like +this in the top level of your Postfix source tree should work: + + % make tidy + % make makefiles CCARGS="-I/usr/local/include -DHAS_LDAP" \ + AUXLIBS_LDAP="-L/usr/local/lib -lldap -L/usr/local/lib -llber" + +If your LDAP shared library is in a directory that the RUN-TIME linker does not +know about, add a "-Wl,-R,/path/to/directory" option after "-lldap". + +Postfix versions before 3.0 use AUXLIBS instead of AUXLIBS_LDAP. With Postfix +3.0 and later, the old AUXLIBS variable still supports building a statically- +loaded LDAP database client, but only the new AUXLIBS_LDAP variable supports +building a dynamically-loaded or statically-loaded LDAP database client. + + Failure to use the AUXLIBS_LDAP variable will defeat the purpose of dynamic + database client loading. Every Postfix executable file will have LDAP + database library dependencies. And that was exactly what dynamic database + client loading was meant to avoid. + +On Solaris 2.x you may have to specify run-time link information, otherwise +ld.so will not find some of the shared libraries: + + % make tidy + % make makefiles CCARGS="-I/usr/local/include -DHAS_LDAP" \ + AUXLIBS_LDAP="-L/usr/local/lib -R/usr/local/lib -lldap \ + -L/usr/local/lib -R/usr/local/lib -llber" + +The 'make tidy' command is needed only if you have previously built Postfix +without LDAP support. + +Instead of '/usr/local' specify the actual locations of your LDAP include files +and libraries. Be sure to not mix LDAP include files and LDAP libraries of +different versions!! + +If your LDAP libraries were built with Kerberos support, you'll also need to +include your Kerberos libraries in this line. Note that the KTH Kerberos IV +libraries might conflict with Postfix's lib/libdns.a, which defines dns_lookup. +If that happens, you'll probably want to link with LDAP libraries that lack +Kerberos support just to build Postfix, as it doesn't support Kerberos binds to +the LDAP server anyway. Sorry about the bother. + +If you're using one of the Netscape LDAP SDKs, you'll need to change the +AUXLIBS line to point to libldap10.so or libldapssl30.so or whatever you have, +and you may need to use the appropriate linker option (e.g. '-R') so the +executables can find it at runtime. + +If you are using OpenLDAP, and the libraries were built with SASL support, you +can add -DUSE_LDAP_SASL to the CCARGS to enable SASL support. For example: + + CCARGS="-I/usr/local/include -DHAS_LDAP -DUSE_LDAP_SASL" + +CCoonnffiigguurriinngg LLDDAAPP llooookkuuppss + +In order to use LDAP lookups, define an LDAP source as a table lookup in +main.cf, for example: + + alias_maps = hash:/etc/aliases, ldap:/etc/postfix/ldap-aliases.cf + +The file /etc/postfix/ldap-aliases.cf can specify a great number of parameters, +including parameters that enable LDAP SSL or STARTTLS, and LDAP SASL. For a +complete description, see the ldap_table(5) manual page. + +EExxaammppllee:: llooccaall((88)) aalliiaasseess + +Here's a basic example for using LDAP to look up local(8) aliases. Assume that +in main.cf, you have: + + alias_maps = hash:/etc/aliases, ldap:/etc/postfix/ldap-aliases.cf + +and in ldap:/etc/postfix/ldap-aliases.cf you have: + + server_host = ldap.example.com + search_base = dc=example, dc=com + +Upon receiving mail for a local address "ldapuser" that isn't found in the / +etc/aliases database, Postfix will search the LDAP server listening at port 389 +on ldap.example.com. It will bind anonymously, search for any directory entries +whose mailacceptinggeneralid attribute is "ldapuser", read the "maildrop" +attributes of those found, and build a list of their maildrops, which will be +treated as RFC822 addresses to which the message will be delivered. + +EExxaammppllee:: vviirrttuuaall ddoommaaiinnss//aaddddrreesssseess + +If you want to keep information for virtual lookups in your directory, it's +only a little more complicated. First, you need to make sure Postfix knows +about the virtual domain. An easy way to do that is to add the domain to the +mailacceptinggeneralid attribute of some entry in the directory. Next, you'll +want to make sure all of your virtual recipient's mailacceptinggeneralid +attributes are fully qualified with their virtual domains. Finally, if you want +to designate a directory entry as the default user for a virtual domain, just +give it an additional mailacceptinggeneralid (or the equivalent in your +directory) of "@fake.dom". That's right, no user part. If you don't want a +catchall user, omit this step and mail to unknown users in the domain will +simply bounce. + +In summary, you might have a catchall user for a virtual domain that looks like +this: + + dn: cn=defaultrecipient, dc=fake, dc=dom + objectclass: top + objectclass: virtualaccount + cn: defaultrecipient + owner: uid=root, dc=someserver, dc=isp, dc=dom + 1 -> mailacceptinggeneralid: fake.dom + 2 -> mailacceptinggeneralid: @fake.dom + 3 -> maildrop: realuser@real.dom + + 1: Postfix knows fake.dom is a valid virtual domain when it looks for this + and gets something (the maildrop) back. + + 2: This causes any mail for unknown users in fake.dom to go to this entry + ... + + 3: ... and then to its maildrop. + +Normal users might simply have one mailacceptinggeneralid and maildrop, e.g. +"normaluser@fake.dom" and "normaluser@real.dom". + +EExxaammppllee:: eexxppaannddiinngg LLDDAAPP ggrroouuppss + +LDAP is frequently used to store group member information. There are a number +of ways of handling LDAP groups. We will show a few examples in order of +increasing complexity, but owing to the number of independent variables, we can +only present a tiny portion of the solution space. We show how to: + + 1. query groups as lists of addresses; + + 2. query groups as lists of user objects containing addresses; + + 3. forward special lists unexpanded to a separate list server, for moderation + or other processing; + + 4. handle complex schemas by controlling expansion and by treating leaf nodes + specially, using features that are new in Postfix 2.4. + +The example LDAP entries and implied schema below show two group entries +("agroup" and "bgroup") and four user entries ("auser", "buser", "cuser" and +"duser"). The group "agroup" has the users "auser" (1) and "buser" (2) as +members via DN references in the multi-valued attribute "memberdn", and direct +email addresses of two external users "auser@example.org" (3) and +"buser@example.org" (4) stored in the multi-valued attribute "memberaddr". The +same is true of "bgroup" and "cuser"/"duser" (6)/(7)/(8)/(9), but "bgroup" also +has a "maildrop" attribute of "bgroup@mlm.example.com" (5): + + dn: cn=agroup, dc=example, dc=com + objectclass: top + objectclass: ldapgroup + cn: agroup + mail: agroup@example.com + 1 -> memberdn: uid=auser, dc=example, dc=com + 2 -> memberdn: uid=buser, dc=example, dc=com + 3 -> memberaddr: auser@example.org + 4 -> memberaddr: buser@example.org + + dn: cn=bgroup, dc=example, dc=com + objectclass: top + objectclass: ldapgroup + cn: bgroup + mail: bgroup@example.com + 5 -> maildrop: bgroup@mlm.example.com + 6 -> memberdn: uid=cuser, dc=example, dc=com + 7 -> memberdn: uid=duser, dc=example, dc=com + 8 -> memberaddr: cuser@example.org + 9 -> memberaddr: duser@example.org + + dn: uid=auser, dc=example, dc=com + objectclass: top + objectclass: ldapuser + uid: auser + 10 -> mail: auser@example.com + 11 -> maildrop: auser@mailhub.example.com + + dn: uid=buser, dc=example, dc=com + objectclass: top + objectclass: ldapuser + uid: buser + 12 -> mail: buser@example.com + 13 -> maildrop: buser@mailhub.example.com + + dn: uid=cuser, dc=example, dc=com + objectclass: top + objectclass: ldapuser + uid: cuser + 14 -> mail: cuser@example.com + + dn: uid=duser, dc=example, dc=com + objectclass: top + objectclass: ldapuser + uid: duser + 15 -> mail: duser@example.com + +Our first use case ignores the "memberdn" attributes, and assumes that groups +hold only direct "memberaddr" strings as in (3), (4), (8) and (9). The goal is +to map the group address to the list of constituent "memberaddr" values. This +is simple, ignoring the various connection related settings (hosts, ports, bind +settings, timeouts, ...) we have: + + simple.cf: + ... + search_base = dc=example, dc=com + query_filter = mail=%s + result_attribute = memberaddr + $ postmap -q agroup@example.com ldap:/etc/postfix/simple.cf \ + auser@example.org,buser@example.org + +We search "dc=example, dc=com". The "mail" attribute is used in the +query_filter to locate the right group, the "result_attribute" setting +described in ldap_table(5) is used to specify that "memberaddr" values from the +matching group are to be returned as a comma separated list. Always check +tables using postmap(1) with the "-q" option, before deploying them into +production use in main.cf. + +Our second use case instead expands "memberdn" attributes (1), (2), (6) and +(7), follows the DN references and returns the "maildrop" of the referenced +user entries. Here we use the "special_result_attribute" setting from +ldap_table(5) to designate the "memberdn" attribute as holding DNs of the +desired member entries. The "result_attribute" setting selects which attributes +are returned from the selected DNs. It is important to choose a result +attribute that is not also present in the group object, because result +attributes are collected from both the group and the member DNs. In this case +we choose "maildrop" and assume for the moment that groups never have a +"maildrop" (the "bgroup" "maildrop" attribute is for a different use case). The +returned data for "auser" and "buser" is from items (11) and (13) in the +example data. + + special.cf: + ... + search_base = dc=example, dc=com + query_filter = mail=%s + result_attribute = maildrop + special_result_attribute = memberdn + $ postmap -q agroup@example.com ldap:/etc/postfix/special.cf \ + auser@mailhub.example.com,buser@mailhub.example.com + +Note: if the desired member object result attribute is always also present in +the group, you get surprising results: the expansion also returns the address +of the group. This is a known limitation of Postfix releases prior to 2.4, and +is addressed in the new with Postfix 2.4 "leaf_result_attribute" feature +described in ldap_table(5). + +Our third use case has some groups that are expanded immediately, and other +groups that are forwarded to a dedicated mailing list manager host for delayed +expansion. This uses two LDAP tables, one for users and forwarded groups and a +second for groups that can be expanded immediately. It is assumed that groups +that require forwarding are never nested members of groups that are directly +expanded. + + no_expand.cf: + ... + search_base = dc=example, dc=com + query_filter = mail=%s + result_attribute = maildrop + expand.cf + ... + search_base = dc=example, dc=com + query_filter = mail=%s + result_attribute = maildrop + special_result_attribute = memberdn + $ postmap -q auser@example.com \ + ldap:/etc/postfix/no_expand.cf ldap:/etc/postfix/expand.cf \ + auser@mailhub.example.com + $ postmap -q agroup@example.com \ + ldap:/etc/postfix/no_expand.cf ldap:/etc/postfix/expand.cf \ + auser@mailhub.example.com,buser@mailhub.example.com + $ postmap -q bgroup@example.com \ + ldap:/etc/postfix/no_expand.cf ldap:/etc/postfix/expand.cf \ + bgroup@mlm.example.com + +Non-group objects and groups with delayed expansion (those that have a maildrop +attribute) are rewritten to a single maildrop value. Groups that don't have a +maildrop are expanded as the second use case. This admits a more elegant +solution with Postfix 2.4 and later. + +Our final use case is the same as the third, but this time uses new features in +Postfix 2.4. We now are able to use just one LDAP table and no longer need to +assume that forwarded groups are never nested inside expanded groups. + + fancy.cf: + ... + search_base = dc=example, dc=com + query_filter = mail=%s + result_attribute = memberaddr + special_result_attribute = memberdn + terminal_result_attribute = maildrop + leaf_result_attribute = mail + $ postmap -q auser@example.com ldap:/etc/postfix/fancy.cf \ + auser@mailhub.example.com + $ postmap -q cuser@example.com ldap:/etc/postfix/fancy.cf \ + cuser@example.com + $ postmap -q agroup@example.com ldap:/etc/postfix/fancy.cf \ + + auser@mailhub.example.com,buser@mailhub.example.com,auser@example.org,buser@example.org + $ postmap -q bgroup@example.com ldap:/etc/postfix/fancy.cf \ + bgroup@mlm.example.com + +Above, delayed expansion is enabled via "terminal_result_attribute", which, if +present, is used as the sole result and all other expansion is suppressed. +Otherwise, the "leaf_result_attribute" is only returned for leaf objects that +don't have a "special_result_attribute" (non-groups), while the +"result_attribute" (direct member address of groups) is returned at every level +of recursive expansion, not just the leaf nodes. This fancy example illustrates +all the features of Postfix 2.4 group expansion. + +OOtthheerr uusseess ooff LLDDAAPP llooookkuuppss + +Other common uses for LDAP lookups include rewriting senders and recipients +with Postfix's canonical lookups, for example in order to make mail leaving +your site appear to be coming from "First.Last@example.com" instead of +"userid@example.com". + +NNootteess aanndd tthhiinnggss ttoo tthhiinnkk aabboouutt + + * The bits of schema and attribute names used in this document are just + examples. There's nothing special about them, other than that some are the + defaults in the LDAP configuration parameters. You can use whatever schema + you like, and configure Postfix accordingly. + + * You probably want to make sure that mailacceptinggeneralids are unique, and + that not just anyone can specify theirs as postmaster or root, say. + + * An entry can have an arbitrary number of mailacceptinggeneralids or + maildrops. Maildrops can also be comma-separated lists of addresses. They + will all be found and returned by the lookups. For example, you could + define an entry intended for use as a mailing list that looks like this + (Warning! Schema made up just for this example): + + dn: cn=Accounting Staff List, dc=example, dc=com + cn: Accounting Staff List + o: example.com + objectclass: maillist + mailacceptinggeneralid: accountingstaff + mailacceptinggeneralid: accounting-staff + maildrop: mylist-owner + maildrop: an-accountant + maildrop: some-other-accountant + maildrop: this, that, theother + + * If you use an LDAP map for lookups other than aliases, you may have to make + sure the lookup makes sense. In the case of virtual lookups, maildrops + other than mail addresses are pretty useless, because Postfix can't know + how to set the ownership for program or file delivery. Your qquueerryy__ffiilltteerr + should probably look something like this: + + query_filter = (&(mailacceptinggeneralid=%s)(!(|(maildrop="*|*") + (maildrop="*:*")(maildrop="*/*")))) + + * And for that matter, even for aliases, you may not want users to be able to + specify their maildrops as programs, includes, etc. This might be + particularly pertinent on a "sealed" server where they don't have local + UNIX accounts, but exist only in LDAP and Cyrus. You might allow the fun + stuff only for directory entries owned by an administrative account, so + that if the object had a program as its maildrop and weren't owned by + "cn=root" it wouldn't be returned as a valid local user. This will require + some thought on your part to implement safely, considering the + ramifications of this type of delivery. You may decide it's not worth the + bother to allow any of that nonsense in LDAP lookups, ban it in the + qquueerryy__ffiilltteerr, and keep things like majordomo lists in local alias + databases. + + query_filter = (&(mailacceptinggeneralid=%s)(!(|(maildrop="*|*") + (maildrop="*:*")(maildrop="*/*"))(owner=cn=root, dc=your, dc=com))) + + * LDAP lookups are slower than local DB or DBM lookups. For most sites they + won't be a bottleneck, but it's a good idea to know how to tune your + directory service. + + * Multiple LDAP maps share the same LDAP connection if they differ only in + their query related parameters: base, scope, query_filter, and so on. To + take advantage of this, avoid spurious differences in the definitions of + LDAP maps: host selection order, version, bind, tls parameters, ... should + be the same for multiple maps whenever possible. + +FFeeeeddbbaacckk + +If you have questions, send them to postfix-users@postfix.org. Please include +relevant information about your Postfix setup: LDAP-related output from +postconf, which LDAP libraries you built with, and which directory server +you're using. If your question involves your directory contents, please include +the applicable bits of some directory entries. + +CCrreeddiittss + + * Manuel Guesdon: Spotted a bug with the timeout attribute. + * John Hensley: Multiple LDAP sources with more configurable attributes. + * Carsten Hoeger: Search scope handling. + * LaMont Jones: Domain restriction, URL and DN searches, multiple result + attributes. + * Mike Mattice: Alias dereferencing control. + * Hery Rakotoarisoa: Patches for LDAPv3 updating. + * Prabhat K Singh: Wrote the initial Postfix LDAP lookups and connection + caching. + * Keith Stevenson: RFC 2254 escaping in queries. + * Samuel Tardieu: Noticed that searches could include wildcards, prompting + the work on RFC 2254 escaping in queries. Spotted a bug in binding. + * Sami Haahtinen: Referral chasing and v3 support. + * Victor Duchovni: ldap_bind() timeout. With fixes from LaMont Jones: + OpenLDAP cache deprecation. Limits on recursion, expansion and search + results size. LDAP connection sharing for maps differing only in the query + parameters. + * Liviu Daia: Support for SSL/STARTTLS. Support for storing map definitions + in external files (ldap:/path/ldap.cf) needed to securely store passwords + for plain auth. + * Liviu Daia revised the configuration interface and added the main.cf + configuration feature. + * Liviu Daia with further refinements from Jose Luis Tallon and Victor + Duchovni developed the common query, result_format, domain and + expansion_limit interface for LDAP, MySQL and PosgreSQL. + * Gunnar Wrobel provided a first implementation of a feature to limit LDAP + search results to leaf nodes only. Victor generalized this into the Postfix + 2.4 "leaf_result_attribute" feature. + * Quanah Gibson-Mount contributed support for advanced LDAP SASL mechanisms, + beyond the password-based LDAP "simple" bind. + +And of course Wietse. + |