de3f761f release 0.92 · by Kevin Montuori

TRIVIAL-LDAP is a one file, all lisp client implementation of parts of
RFC 2251 - Lightweight Directory Access Protocol (v3).  


It should be noted from the start that my intent when I began was not
to provide a full featured LDAP library per se; rather, I required
some functionality for a different project altogether and was unable
to locate a Common Lisp LDAP client implementation.  I've implemented
more of the protocol than I actually required, but stopped short of a
full implementation.  The omissions I am aware of are:

  - UTF-8 is not implemented
  - the SASL authentication method is not implemented
  - controls are not implemented
  - extended DN searches are not implemented
  - referrals are not followed (searches returning referrals will 
    simply no-op following the referrals).  
  - extended request/response is not implemented, 
    beyond handling a notice of disconnection.

If there is any interest I would consider augmenting trivial-ldap with
the missing functionality.  

Further, just enough BER encoding/decoding is implemented to handle
LDAP.  I'm not sure that it would be all that difficult to implement a
stand-alone BER library, but it was tangental to the problem I was
looking to solve.

Finally, I'm fairly new to programming in Common Lisp.  It is entirely
possible that this code is really awful, slow, unidiomatic, and unfit
for consumption; and worse, i'm not a library writer at all (I spend
my days writing glue code and what would have been shell scripts if
this were 1987). If there are any suggestions of how I might go about
making the code more "lispy" or providing a more useful API drop me a
line and give me a clue.


kevin montuori


TRIVIAL-LDAP is Copyright 2005-2006 Kevin Montuori

This package is redsitributable under the terms of The Clarified
Artistic License, a copy of which should have been included in the


TRIVIAL-LDAP comprises one lisp source file, which should be compiled
and loaded.  Alternatively, the distribution contains an asdf file in
case that's more handy.

There are two third-party library requirements:

  trivial-sockets   http://www.cliki.net/trivial-sockets
  cl-ppcre          http://www.cliki.net/CL-PPCRE

(trivial-sockets is not in any way related to trivial-ldap except for
the "trivial-" prefix, which I liked and thought appropriate.)

I have tested with openmcl (1.0) and sbcl (0.9.7) on OS X, against an
openldap directory server (slapd 2.2.19).  


There are two classes implemented, LDAP and ENTRY.  An instance of the
LDAP class represents a LDAP server (and connection) while the latter
represents an instance of a directory entry.  There are two types of
public methods: those prefixed with "ldap/" are the lower-level
methods and should be though of as "operating on the directory."
Those with an "entry/" prefix are higher level and can be thought of
as operating on an entry.  

Note that if a Notice of Disconnection is received, this client will
immediately sever the connection from the LDAP server.  Whatever LDAP
response code (e.g., protocolError) and message will be returned if it
is appropriate.


  ldap/new &key (host "localhost") (port 389) user pass base debug
     creates a new ldap object.  host and port should be self
     explanatory.  :user and :pass are strings representing the DN and
     password to bind with.  :base provides a default search base.  If
     :debug is t debugging messages will be printed to *debug-io*.

  ldap/host ldap-obj
  ldap/port ldap-obj
  ldap/user ldap-obj
  ldap/pass ldap-obj
  ldap/base ldap-obj
  ldap/debug ldap-obj
    get/set each of the ldap object's attributes

  ldap/bind ldap-obj
    bind to the ldap server.

  ldap/unbind ldap-obj
    unbind from the ldap server and close the stream

  ldap/abandon ldap-obj
    abandon the current request and trash bytes waiting to be read

  LDAP operations:  each of these methods returns three values: 

    first: t or nil: incicates whether of not the operation was 
           successful, from the LDAP directory server's point of view.

    second: the name of the result code (see +ldap-result-codes+ for a
            list of code names & numbers).

    third: any message the LDAP directory server returned.

  ldap/add ldap-obj entry-obj
    add entry-obj to the directory
  ldap/delete ldap-obj entry-obj
    delete entry-obj from the directory

  ldap/moddn ldap-obj dn-or-entry new-rdn  &key (delete-old nil)
    modify the RDN of a directory entry.  The entry to be modified may
    be specified as an entry object or as a DN string.  If :delete-old 
    is t, the old RDN attribute will be removed.

  ldap/compare ldap-obj dn-or-entry attribute value
    send a compare request.  The directory entry in question may be 
    specified as an entry object or as a DN string.  The attribute may be
    a symbol or string.  Returns t if the response code from the LDAP 
    directory server is compareTrue and nil otherwise.  If the request was
    successful but the assertion failed, the second return value will 
    be compareFalse

  ldap/modify ldap-obj dn-or-entry list-of-mods
    modify a directory entry.  The directory entry may be specified as 
    an entry object of as a DN string.  The list-of-mods will be a list
    of three element lists: (type attribute value) where type will be 
    one of the symbols ADD, DELETE, or REPLACE.  

  ldap/search ldap-obj filter &key base (scope 'SUB) (deref 'NEVER)
              (size-limit 0) (time-limit 0) (types-only nil) attributes
    search a directory server.  The filter should be a valid LDAP filter 
    but please note that extended filters are NOT implemented.  The 
    parentheses must be balanced however the outer parentheses may be 
    omitted (i.e., "cn=quux" and "(cn=quux)" are the same filter.  
    :base defaults to the value of the ldap-obj's base attribute.
    :scope may be one of BASE, ONE, or SUB
    :deref may be one of NEVER, SEARCH, FIND, or ALWAYS
    :size-limit and :time-limit are integers
    :types-only should be t or nil
    :attributes should be a list of attributes to return

    ldap/search returns three values:

      first: list of entry objects, or an empty list if no 
             matches are found

      second: the LDAP response name
      third: any message sent from the directory server

  ldap/ldif-search (macro: arguments as for ldap/search, above)
    returns an LDIF string containing the search results

  entry/new DN-string &key attrs (infer-rdn t)
    create a new entry object.  Attributes are specified as an alist:

     :attr '((l . ("Boston" "Cambridge")) 
             (objectclass . organizationalunit))

    note that attribute names may be either strings or symbols but
    will be converted to symbols internally.  if :infer-rdn is not
    nil the RDN attribute will be appended to the attribute alist.  

  entry/rdn entry-obj
    return the entry's RDN.  To change the entry's RDN, however, 
    see entry/chagne-rdn below.

  entry/change-rdn entry-obj new-rdn
    change the RDN (and therefore DN) of an entry object, but do not 
    send a moddn message to the LDAP directory.

  entry/attr-value entry-obj attribute
    return list of values for the specified attribute.  A list is always
    returned, even if there is only one value associated with 
    the attribute.

  entry/attr-list entry-obj
    return a list of an entry's attributes, as symbols.

  entry/ldif entry-obj
    return a LDIF string representation of an entry object.

  ENTRY operations: these methods return t or nil, or throw the error
  LDAP-RESPONSE-ERROR if the LDAP directory server returns an error
  status.  Arguments are described in the LDAP section above.

  entry/add entry-obj ldap-obj
    add an entry to the LDAP directory.

  entry/delete entry-obj ldap-obj
  entry/delete DN-string ldap-obj
    delete an entry from the LDAP directory.

  entry/moddn entry-obj ldap-obj new-rdn &key delete-old
    modify a directory entry's RDN.  This method (unlike ldap/moddn)
    also modifies the entry object's attributes accordingly.

  entry/compare entry-obj ldap-obj attribute value
  entry/compare DN-string ldap-obj attribute value
    issuse a compare request.  Returns t if compareTrue, nil if 
    compareFalse, and throws an error otherwise.

  entry/modify entry-obj ldap-obj list-of-mods
    modifies a directory entry's attributes.  This method, (unlike
    ldap/modify) modifies the entry object's attriibutes if the LDAP
    request succeeds.