


NeoTcl Lightweight Directory Access Protocol Interface Routines

Version 1.0

$Id: neoXldap.txt,v 1.1.1.1 1999/03/31 20:34:37 damon Exp $

OVERVIEW

The Lightweight Directory Access Protocol provides TCP/IP access to
X.500 directory services and/or to a stand-alone LDAP server.

This code provides a Tcl interface to the freely redistributable
Lightweight Directory Access Protocol package from the University of 
Michigan.  (http://www.umich.edu/~rsug/ldap)

It was written by Karl Lehenbauer, of NeoSoft, Inc., in August and
September of 1997.

FOR MORE INFORMATION

This document principally describes how to use our Tcl interface to the 
LDAP library works.

For more information on LDAP and the University of Michigan LDAP package,
please visit the website mentioned above.  The package includes substantial
documentation in the form of UNIX manual pages, a SLAPD/SLURPD guide
in Adobe Portable Document Format (pdf), and a number of Internet RFCs
related to LDAP services.

IMPLEMENTATION DECISIONS

Because I used the new "Tcl object" C interfaces, this package only works
with Tcl 8.0 or above.

This package interfaces with the University of Michigan LDAP protocol
package, version 3.3, an implementation of version 2 of the LDAP protocol.

Although an LDAP client (or server) could be written in native Tcl 8.0,
as Tcl 8.0 and above can do binary I/O, and Tcl 8 and above have strings 
that are fully eight-bit clean, for a first implementation, to minimize 
compatibility problems, I have created a C interface to the UMich LDAP library.

A native Tcl implementation would be cool because we could bring the receiving
of messages into the normal Tcl event loop and run the LDAP interface fully
asynchronous.

This implementation is blocking, and blocking only.  That is to say that
the Tcl event loop is frozen while the ldap routines are waiting on data.

This could be fixed either by recoding all of the I/O in the LDAP library
to use Tcl's I/O system instead, or by simply coding the LDAP interface in
native Tcl, as mentioned above.

Another advantage of coding in high-level Tcl, of course, is that the
client would immediately be cross-platform to Windows and the Mac, as
well as Unix.

Binary data is not currently supported.  It will probably be trivial to 
add, I just haven't dug into it yet.

CONNECTING TO AN LDAP SERVER

To create an ldap interface entity, we use the "ldap" command.

    ldap open foo foo.bar.com

This opens a connection to a LDAP server on foo.bar.com, and makes
a new Tcl command, foo, through which we will manipulate the interface
and make queries to the remote LDAP server.

    ldap init foo foo.bar.com

Same as above, foo is created, but for "init", opening the connection is 
deferred until we actually try to do something.

For the purposes of this example, we're going to assume that "foo" is the
command created by opening a connection using "ldap open".

Note:  I'm particularly dissatisfied with the syntax of this option,
so it is one of the most likely things to change in a subsequent release.

BINDING

After a connection is made to an LDAP server, an LDAP bind operation must
be performed before other operations can be attempted over the connection.

Both simple authentication and kerberos authentication are available.
LDAP version 3 supports many new "SSL"-style authentication and encryption
systems, which are not currently supported by the UMich server, and hence
by this interface package.

Currently simple authentication, and kerberos-based authentication, are
supported.

To use LDAP and still have reasonable security in a networked, 
Internet/Intranet environment, secure shell can be used to setup
secure, encrypted connections between client machines and the LDAP
server, and between the LDAP server and any replica or slave servers
that might be used.

To perform the LDAP "bind" operation to establish a distinguished name
and password that we'll be known as:

    foo bind simple dn password

    foo bind kerberos_ldap
    foo bind kerberos_dsa
    foo bind kerberos_both

It either returns nothing (success), or a Tcl error with appropriate error
text.

For example,

    foo bind simple "cn=Manager, o=NeoSoft Inc, c=us" "secret"

If you attempt to bind with one of the kerberos authentication types
described above and your LDAP library was not built with KERBEROS
defined, you will get an unknown auth type error.

To unbind an LDAP connection previously bound with "bind":

    foo unbind

Note that unbinding an already unbound, or never-bound, connection results 
in freeing memory twice and other nasties.  Right now, neither the LDAP 
Tcl interface nor the LDAP library appear to know when the unbind is legal 
to perform and when it is not, so beware...

The ability of the library to callback to the client, enabling re-binding
while following referrals, is not currently supported.

DELETING OBJECTS

To delete an object in the LDAP database, use

    foo delete dn

To rename an object to another relative distinguished name, use

    foo rename_rdn dn rdn

To rename an object to another relative distinguished name, leaving
the old entry as some kind of attribute (FIX: not sure if this is
right or how it works)

    foo modify_rdn dn rdn


ADDING NEW OBJECTS

    foo add dn attributePairList

This creates a new distinguished name and defines zero or more attributes.

"attributePairList" is a list of key-value pairs, the same as would
be returned by "array get" if an array had been set up containing the
key-value pairs.  Note that, right now, the sort of lowest-level pair
of the DN must also appear in the attributePairList, as in:

    foo add "cn=karl, ou=People, o=NeoSoft Inc, c=US" {cn karl ...}

ADDING, DELETING, AND REPLACING OBJECT ATTRIBUTES

You can have multiple occurrences of the same attribute in a record.
These are represented in search results, through the Tcl interface,
as a list.

    foo add_attributes dn attributePairList

This adds key-value pairs to an existing DN.  If an attribute being
added already exists, the new value will be appended to the list.

    foo replace_attributes dn attributePairList

This replaces specified key-value pairs in an existing DN, leaving
unnamed ones untouched.

    foo delete_attributes dn attributePairList

This deletes attributes in the list.  If a pair is "foo {bar snap}" and
you delete "foo bar", "foo" will still have "snap".

If you provide an empty string ("") for the value part of the key-value
pair, the entire attribute will be deleted.  To reiterate, if you provide
a non-empty string for the value part, only that value will be removed
from the value list.

SEARCHING

The Tcl interface to searching takes a control array, which contains
a couple of mandatory key-value pairs, and can contain a number of
optional key-value pairs as well, for controlling the search, a
destination array, into which the specified attributes (or all attributes
of matching DNs if none are specified) and values are stored.

The "code" part is executed repeatedly, once for each DN matching the
search criteria.

    foo search controlArray destArray code

	Using data in the control array, a search is performed of the
	LDAP server opened when foo was created.  Possible elements
	of the control array are enumerated blow.

	controlArray(base) is the DN being searched from. (required)

	controlArray(filter) contains the search criteria. (required)

	controlArray(scope) must be "base", "one_level", or "subtree".
	    If not specified, scope defaults to "subtree".

	controlArray(deref) must be "never", "search", "find", or "always"
	    If not specified, deref defaults to "never"

	controlArray(attributes) is a list of attributes to be fetched.
	    If not specified, all attributes are fetched.

        For each matching record, destArray is populated with none,
	some or all attribute-value pairs.

Note:  There are some additional parameters that can be set, such as
how long the synchronous version of the routines should wait before
timing out, the interfaces for which are not available in the current
version.

CACHING (Note: Netscape clients do not have caching interfaces).

The UMich LDAP library offers the client application fairly fine-
grained control of caching of results retrieved from searches, 
offering significant performance improvement and reduced
network traffic.

By default, the cache is disabled.

To enable caching of data received from an LDAP connection,

    foo cache enable timeout maxmem

	...where timeout is specified in seconds, and maxmem is the
	maximum memory to be used fo caching, in bytes.

	If maxmem is 0, the cache size is restricted only by the timeout.

    foo cache disable

	...temporarily inhibits use of the cache (while disabled, new requests
	are not cached and the cache is not checked when returning results).

	Disabling the cache does not delete its contents.

    foo cache destroy

	...turns off caching and completely removes the cache from memory.

    foo cache flush

	...deletes the entire cache contents, but does not affect
	whether or not the cache is being used.

    foo cache uncache dn

	...removes from the cache all request results that make reference 
	to the specified DN.

	This should be used, for example, after doing an add_attributes,
	delete_attributes, or replace_attributes (ldap_modify(3)) 
	involving the requested DN.

    foo cache no_errors

	...suppresses caching of any requests that result in an error.

    foo cache size_errors

	...suppresses caching of any requests that result in an error,
	except for requests resulting in "sizelimit exceeded", which 
	are cached.  This is the default.

    foo cache all_errors

        ...enables caching of all requests, including those that result
	in errors.


