BUILDING WITH LDAP SUPPORT
==========================

You need to have LDAP libraries and include files installed somewhere on
your system, and you need to configure the Postfix Makefiles
accordingly.

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 should work:

    % make tidy
    % make makefiles CCARGS="-I/some/where/include -DHAS_LDAP" \
	    AUXLIBS="/some/where/libldap.a /some/where/liblber.a"

The `make tidy' command is needed only if you have previously built
Postfix without LDAP support.

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 yet 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 -R option so the executables can find
it at runtime.

USING LDAP LOOKUPS
==================

In order to use LDAP lookups, define at least one LDAP source as a table
lookup in main.cf, for example:

    alias_maps = hash:/etc/aliases, ldap:ldapsource

Each LDAP source can have the following parameters, which should be
prefixed in main.cf with the name you've given the source in its
definition. To continue the example, the first parameter below,
"server_host", would be defined in main.cf as "ldapsource_server_host". 
Defaults are given in parentheses:

    server_host (localhost)
    	The name of the host running the LDAP server, e.g.
		ldapsource_server_host = ldap.your.com
	It should be possible with all the libraries mentioned above to 
	specify multiple servers separated by spaces, with the libraries
	trying them in order should the first one fail.

    server_port (389) 
    	The port the LDAP server listens on, e.g.
		ldapsource_server_port = 778

    search_base (no default)
    	The base at which to conduct the search, e.g. 
		ldapsource_search_base = dc=your, dc=com

    timeout (10 seconds)
    	The number of seconds a search can take before timing out, e.g.
		ldapsource_timeout = 5
    	
    query_filter (mailacceptinggeneralid=%s)
    	The RFC2254 filter used to search the directory, where %s is a 
	substitute for the address Postfix is trying to resolve, e.g.
		ldapsource_query_filter = (&(mail=%s)(paid_up=true))

    result_attribute (maildrop)
	The attribute Postfix will read from any directory entries
	returned by the lookup, to be resolved to an email address.
		ldapsource_result_attribute = mailbox

    bind (yes)
    	Whether or not to bind to the LDAP server. Newer LDAP
	implementations don't require clients to bind, which saves
	time. Example:
		ldapsource_bind = no

    bind_dn ("")
    	If you do have to bind, do it with this distinguished name.
	Example:
		ldapsource_bind_dn = uid=postfix, dc=your, dc=com

    bind_pw ("")
    	The password for the distinguished name above. If you have to
	have this, you probably want to make main.cf readable only by
	the Postfix user. Example:
		ldapsource_bind_pw = postfixpw

Don't use quotes in these variables; at least, not until the Postfix
configuration routines understand how to deal with quoted strings.

EXAMPLE
=======

Here's a basic example. In main.cf, you have these configuration
parameters defined:

alias_maps = hash:/etc/aliases, ldap:ldapsource
ldapsource_server_host = ldap.my.com
ldapsource_search_base = dc=my, 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.my.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.

NOTES AND THINGS TO THINK ABOUT
===============================

- 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 maildrops. Maildrops can also
  be comma-separated lists of addresses. 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=my, dc=com
  cn: Accounting Staff List
  o: my.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 like "|/some/program" are pretty useless. Your query_filter
  should probably look something like this:

  virtual_query_filter = 
  	(&(mailacceptinggeneralid=%s)(!(|(maildrop="*|*")(maildrop="*:*"))))

- And for that matter, you may not want users able to specify their
  maildrops as programs, particularly if they'd be executed on the
  server. A safer local query_filter could look something like:

  local_query_filter = (&(mailacceptinggeneralid=%s)(|(!(maildrop="*|*"))(owner=cn=root, dc=your, dc=com)))

  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
  probably require some thought on your part to implement safely,
  considering the ramifications of includes and programs. You may decide
  it's not worth the bother to allow any of that nonsense in LDAP
  lookups, ban it in the query_filter, and keep things like majordomo
  lists in local alias databases.

- It's not yet known how all this scales, but LDAP lookups are much more
  expensive than checking a DB file. If you anticipate a lot of lookups,
  it may pay to plan your directory to reduce the number of lookups. For
  instance, rather than having a bunch of objects that serve as aliases
  to just one object, you could simply add their mailacceptinggeneralids
  to the target object. This:

  	dn: uid=firstlast, dc=your, dc=com
	maildrop: firstlast@mailbox.your.com
	mailacceptinggeneralid: firstlast
	mailacceptinggeneralid: First.Last
	mailacceptinggeneralid: F.Last

  Not this:
  
  	dn: uid=firstlast, dc=your, dc=com
	maildrop: firstlast@mailbox.your.com
	mailacceptinggeneralid: firstlast

  	dn: cn=First.Last, dc=your, dc=com
	maildrop: firstlast
	mailacceptinggeneralid: First.Last

  	dn: cn=F.Last, dc=your, dc=com
	maildrop: firstlast
	mailacceptinggeneralid: F.Last

  Any performance reports will be much appreciated on the postfix-users
  list.

  UPDATE: At Merit, I've seen over 150000 deliveries per day with no
  noticeable delay from our OpenLDAP server. I'd now recommend not
  resorting to the above unless you anticipate much more traffic than
  that. It makes management of your directory less intuitive, which is
  probably not worth the reduction in lookups.

CREDITS
=======

Support for LDAP was initially written by Prabhat K Singh of VSNL,
Bombay, India, and then hideously bloated by John Hensley to support
multiple sources and more configurable attributes. The caching bits were
initially worked out by Prabhat, then munged to support the multiple
sources. Other contributions have been submitted to move toward better
support of Netscape/LDAPv3 libraries, and any other improvements are of
course welcome.
