Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: master
Fetching contributors…

Cannot retrieve contributors at this time

557 lines (450 sloc) 18.701 kb
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<!--
(defun add-api-entry ()
(interactive)
(let ((function (read-string "Function/Method name: "))
(args (read-string "Argument list: "))
(type (read-string "Function, Method, or Macro? ")))
(insert (format "
<dt>
<span class=\"term\"><b>%s</b> <i>%s</i></span>
<span class=\"type\">[%s]</span>
</dt>
<br class=\"both\" />
<dd>
</dd>" function args type))
(previous-line 1)))
-->
<html>
<head>
<title>TRIVIAL-LDAP v0.92</title>
<style type="text/css">
.leftcontent {float: left; width: 75%; padding-left: 12px;}
div.head {background-color: #aeffee;}
span.term {float: left; text-align: left;}
span.type {float: right; text-align: right; font-weight: bold;}
br.both {clear: both;}
dd {font-style: normal; padding-bottom: 8px;}
</style>
</head>
<body class="leftcontent">
<h3>TRIVIAL-LDAP v0.92</h3>
TRIVIAL-LDAP is a one file, all Common Lisp client implementation of
parts of RFC 2261.
<h4>WARNING:</h4> This is beta software. While I believe the API
documented below is correct it is subject to change. Also, <b>do
not run execute the example.lisp program against a production LDAP
directory, it will delete your entries.</b>
<h4>Introduction</h4> This LDAP client came about as a result of
some functionality I required for a different project altogether.
As a result it provides functionality that is general enough but
probably not in typical low-level API fashion. (For instance, a
"real" LDAP library would probably tackle the BER encoding
separately.) However, as there is a lack of Common Lisp LDAP
clients out there I thought I'd share. <p/>
I am open to both requests for features and suggestions for
improving my Lisp code. There are features I will be implementing
in the short term but for the sake of not creating false
expectations neither a comprehensive list nor timeframe is
available. <p />
You can reach me at montuori@gmail.com.
<h4>Changes</h4>
<dl>
<dt>2009-10-23 (v0.92)</dt>
<dd>Applied a patch supplied by Far&eacute; to provide support for
XCVB</dd>
<dt>2009-08-16 (v0.91)</dt>
<dd>Applied a patch supplied by Nick Dannenberg to fix UTF-8
handling for SBCL and CCL. My sincerest appreciation for taking
the time to generate and send the patch along!</dd>
<dt>2009-03-12 (v0.90)</dt>
<dd>Applied patches kindly provided by Slawek Zak.
<ul>
<li>Enable UTF-8 encoding for Allegro.</li>
<li>Fixed a compilation failure on Allegro where a number
of constants were not properly defined.</li>
<li>Fixed the dosearch macro for cases where the LDAP
variable is lexical.</li>
</ul>
Thanks to Slawek for taking the time to send the patches!
</dd>
<dt>2007-01-12 (v0.80)</dt>
<dd><ul>
<li>Converted from trivial-socket to usocket: indications
were that trivial-socket has been deprecated.</li>
<li>Added support for SSL with CL+SSL. Setting the ldap
object slot <code>sslflag</code> to T or
the <code>port</code> slot to 636 will force an encrypted
connection. Do note that this is not TLS, just ldaps://
... I don't require TLS; if you do, drop me a line.</li>
<li>Added functionality to ease the pain of short slapd
idletimeouts. The ldap object
slot <code>reuse-connection</code> may be set to NIL (the
default) to not attempt reopening connections, T to reopen
the connection before each request, or TRIVIAL-LDAP:REBIND
if the connection should be opened and a bind message sent
before each request (except, of course, the bind request
itself). </li>
<li>A couple of documentation and logic bugs were corrected</li>
</ul></dd>
</dl>
<p>
<h4>Acknowledgments</h4> I would like to thank Zach Beane for his
many helpful comments and suggestions. Thanks also to Ed Symanzik
for pointing out a number inconsistencies in the code and
documentation.
<p>
<h4>License</h4> TRIVIAL-LDAP is distributed under the Clarified
Artistic License, a copy of which is included in the downloadable
package.
<h4>Requirements</h4> TRIVIAL-LDAP has been tested under OpenMCL 1.0
(OS X/PPC), SBCL 0.9.7 (OS X/PPC), and SBCL 1.0 (OS X/Intel).
<p>
I would assume any CL that is supported by usockets and CL+SSL
would have no issues with this code. If you encounter problems
let me know.
<p/>Two external packages, usocket and CL+SSL, are required.
CL+SSL itself requires trivial-gray-streams, flexi-streams, and
cffi. These may be downloaded from:
<ul>
<li><a href="http://common-lisp.net/project/usocket/">
http://common-lisp.net/project/usocket/</a></li>
<li><a href="http://common-lisp.net/project/cl-plus-ssl/">
http://common-lisp.net/project/cl-plus-ssl/</a></li>
<li><a href="http://common-lisp.net/project/cffi/">
http://common-lisp.net/project/cffi/</a></li>
<li><a href="http://weitz.de/flexi-streams/">
http://weitz.de/flexi-streams/</a></li>
</ul>
The trivial-gray-streams project is part of the CL+SSL project.
(Note: to get CL+SSL working on OS X/Intel it was necessary to
re-compile openssl with the -m64 flag.)
<p>
<h4>Limitations</h4>
Missing functionality, as specified by RFC 2251, includes:
<ul>
<li>UTF-8 is not implemented for all CL implementations</li>
<li>SASL authentication is not implemented</li>
<li>controls are not implemented</li>
<li>extended DN searches are not implemented</li>
<li>referrals are not followed</li>
<li>extended request/response is not implemented</li>
</ul>
I do not require this functionality myself, but if there was
interest I would consider augmenting TRIVIAL-LDAP with some of
this missing functionality.
<p/>
<h4>API</h4>
<dl>
<p><b>LDAP object and associated methods.</b></p>
<dt>
<span class="term"><b>new-ldap</b> <i>&key (host "localhost")
(port 389) user pass base debug</i></span> <span
class="type">[function]</span>
</dt>
<br class="both" />
<dd>Return an LDAP object.</dd>
<dt>
<span class="term"><b>host</b> <i>ldap-object</i></span>
<span class="type">[method]</span>
</dt>
<br class="both" /> <dd>Get/set the host slot value of
ldap-object. Slot value will be a string.</dd>
<dt>
<span class="term"><b>port</b> <i>ldap-object</i></span> <span
class="type">[method]</span>
</dt>
<br class="both" /> <dd>Get/set the port slot value of
ldap-object. Slot value will be an integer. If the sslflag slot
is NIL, defaults to 389; if sslflag slot is T, defaults to 636.
If the port parameter is manually set to 636 an SSL connection is
used unless the sslflag is explicitly set to nil.
</dd>
<dt>
<span class="term"><b>user</b> <i>ldap-object</i></span> <span
class="type">[method]</span>
</dt>
<br class="both" /> <dd>Get/set the user DN to bind as. Slot
value will be a string.
</dd>
<dt>
<span class="term"><b>pass</b> <i>ldap-object</i></span> <span
class="type">[method]</span>
</dt>
<br class="both" /> <dd>Get/set the simple password to bind with.
Slot value will be a string.
</dd>
<dt>
<span class="term"><b>base</b> <i>ldap-object</i></span> <span
class="type">[method]</span>
</dt>
<br class="both" /> <dd>Get/set the default base DN for searches.
Slot value will be a string.
</dd>
<dt>
<span class="term"><b>debugflag</b> <i>ldap-object</i></span>
<span class="type">[method]</span>
</dt>
<br class="both" />
<dd>Get/set the debug flag. Slot value will be T or NIL. When
value is T debug output will be written to *debug-io*.
</dd>
<dt>
<span class="term"><b>sslflag</b> <i>ldap-object</i></span>
<span class="type">[method]</span>
</dt>
<br class="both" />
<dd>Get/set the SSL flag. When T the default port is 636 and a
CL+SSL stream is used. Defaults to nil. Note that if the port
slot is explicitly set to 636 an SSL connection is used unless the
sslflag slot is set to nil explicitly.
</dd>
<dt>
<span class="term"><b>reuse-connection</b> <i>ldap-object</i></span>
<span class="type">[method]</span>
</dt>
<br class="both" />
<dd>Get/set the reuse-connection slot parameter. When T re-open
the stream before each reqest; when LDAP:REBIND open the stream
and send an (ldap:bind ldap-object) message; when nil, don't do
anything special. Set to NIL by default.
</dd>
<p><b>Entry object and associated methods</b></p>
<dt>
<span class="term"><b>new-entry</b> <i>dn &key (attrs ())
(infer-rdn t)</i></span> <span class="type">[function]</span>
</dt>
<br class="both" />
<dd>Return a new entry object with the DN specified.
<code>attrs</code>, if specified, will be an alist of
attribute/value pairs. If <code>infer-rdn</code> is T the RDN
attribute and value will be appended to the attribute list.
</dd>
<dt>
<span class="term"><b>dn</b> <i>entry-object</i></span>
<span class="type">[method]</span>
</dt>
<br class="both" />
<dd>Return the DN value for entry-object.
</dd>
<dt>
<span class="term"><b>rdn</b> <i>entry-object</i></span>
<span class="type">[method]</span>
</dt>
<br class="both" />
<dd>Return the RDN value for entry-object
</dd>
<dt>
<span class="term"><b>change-rdn</b> <i>entry-object
new-rdn</i></span> <span class="type">[method]</span>
</dt>
<br class="both" /> <dd>Change the RDN (and therefore DN) of an
entry-object. The RDN attribute and value will be updated in the
attribute list. No LDAP directory transactions will take place.
</dd>
<dt>
<span class="term"><b>attr-list</b> <i>entry-object</i></span>
<span class="type">[method]</span>
</dt>
<br class="both" /> <dd>Return the list of attribute symbols
belonging to entry-object
</dd>
<dt>
<span class="term"><b>attr-value</b> <i>entry-object
attr</i></span> <span class="type">[method]</span>
<br class="both" />
<span class="term"><b>attr-value</b> <i>entry-object
attr-list</i></span> <span class="type">[method]</span>
</dt>
<br class="both" /> <dd>Return a list of values associated with
the attribute <code>attr</code>. Return NIL if the attribute does
not exist. If a list of attributes is passed, return a list of
lists of values.
</dd>
<dt>
<span class="term"><b>add-attr</b> <i>entry-object attr
values</i></span> <span class="type">[method]</span>
</dt>
<br class="both" /> <dd>Add the specified attribute with the value
or values specified to the entry object's attribute list. Returns
the entire list of attributes/values. No LDAP directory transactions
will take place.
</dd>
<dt>
<span class="term"><b>del-attr</b> <i>entry-object attr
&optional values</i></span> <span class="type">[method]</span>
</dt>
<br class="both" /> <dd>Delete the specified attribute (or values
for attribute) from the entry object's attribute list. Returns
the entire list of attributes/values. No LDAP directory
transactions will take place.
</dd>
<dt>
<span class="term"><b>replace-attr</b> <i>entry-object attribute
values</i></span> <span class="type">[method]</span>
</dt>
<br class="both" /> <dd>Replace current attribute values with
values specified. Returns the entire list of attributes/values.
No LDAP directory transactions will take place.
</dd>
<dt>
<span class="term"><b>ldif</b> <i>entry-object</i></span>
<span class="type">[method]</span>
</dt>
<br class="both" />
<dd>Return an LDIF representation of entry (as a string).
</dd>
<p><b>LDAP Commands</b></p>
<p>
<b>NB:</b> Methods below that are specialized first on ldap-object will
return three values: T/NIL indicating success or failure, the LDAP
response code (these are exported from the TRIVIAL-LDAP package as
symbols), and third, any response message received from the LDAP
directory server (as a string).
</p>
<p>
Methods specialized first on entry-object will return T (or T/NIL
in the case of compare) and will throw an ldap-response-error if a
response from the LDAP directory server is other than succesful.
</p>
<p>
<i>dn-or-entry</i> can be either an entry-object or a DN string.
<i>dn</i> is a string. Generally if the method only requires the DN
either the entry or the DN will be acceptable arguments.
</p>
<dt>
<span class="term"><b>bind</b> <i>ldap-object</i></span>
<span class="type">[method]</span>
</dt>
<br class="both" />
<dd>Send a bind request to the LDAP directory server.
</dd>
<dt>
<span class="term"><b>unbind</b> <i>ldap-object</i></span>
<span class="type">[method]</span>
</dt>
<br class="both" /> <dd>Send an unbind request to the LDAP
directory server and close the stream.
</dd>
<dt>
<span class="term"><b>abandon</b> <i>ldap-object</i></span>
<span class="type">[method]</span>
</dt>
<br class="both" /> <dd>Send an abandon request to the LDAP
directory server and purge any data on the stream waiting to be
read. </dd>
<dt>
<span class="term"><b>add</b> <i>ldap-object entry-object</i></span>
<span class="type">[method]</span>
<br class="both" />
<span class="term"><b>add</b> <i>entry-object ldap-object</i></span>
</dt>
<br class="both" /> <dd>Add an entry described by entry-object to
the directory specified by ldap-object.
</dd>
<dt>
<span class="term"><b>delete</b> <i>ldap-object
dn-or-entry</i></span> <span class="type">[method]</span>
<br class="both" />
<span class="term"><b>delete</b> <i>entry-object
ldap-object</i></span>
<br class="both" />
<span class="term"><b>delete</b> <i>dn ldap-object</i></span>
</dt>
<br class="both" /> <dd>Delete entry from directory specified by
ldap-object. <code>dn-or-entry</code> may be an entry object or a
DN string.
</dd>
<dt>
<span class="term"><b>moddn</b> <i>ldap-object dn-or-entry
new-rdn &key delete-old new-sup</i></span> <span
class="type">[method]</span>
<br class="both" />
<span class="term"><b>moddn</b> <i>entry-object ldap-object
new-rdn &key delete-old new-sup</i></span>
<br class="both" />
<span class="term"><b>moddn</b> <i>dn ldap-object new-rdn &key
delete-old new-sup</i></span>
</dt>
<br class="both" /> <dd>Modify the RDN specified by
<code>dn-or-entry</code> to the replacement RDN
<code>new-rdn</code>. <code>dn-or-entry</code> may be either an
entry object or DN string. If an object is specified, the DN and
attribute associated with the RDN slot values are modified as well
as the directory specified by ldap-object.
</dd>
<dt>
<span class="term"><b>compare</b> <i>ldap-object dn-or-entry
attribute value</i></span> <span class="type">[method]</span>
<br class="both" /> <span class="term"><b>compare</b>
<i>entry-object ldap-object attribute value</i>
</dt>
<br class="both" /> <dd>Send a compare message to the directory
server asserting that entry-obj (or DN) has an attribute
<code>attribute</code> with a value <code>value</code>. Returns
either T or NIL (as the only argument or as the first argument)
indicating a return code of compareTrue or compareFalse.
</dd>
<dt>
<span class="term"><b>modify</b> <i>ldap-object dn-or-entry
list-of-mods</i></span> <span class="type">[method]</span>
<br class="both" />
<span class="term"><b>modify</b> <i>entry-object ldap-object
list-of-mods</i></span>
</dt>
<br class="both" /> <dd>Modify the entry specified by
<code>dn-or-entry</code> or <code>entry-object</code>.
<code>list-of-mods</code> is a list of (type attribute value)
triples. Type will be one of ldap:add, ldap:delete, or
ldap:replace.
</dd>
<dt>
<span class="term"><b>search</b> <i>ldap-object filter &key base
(scope 'sub) (deref 'never) (size-limit 0) (time-limit 0)
types-only attributes</i></span> <span
class="type">[method]</span>
</dt>
<br class="both" /> <dd>Search the directory specified by
ldap-object. <code>filter</code> is an LDAP filter (as a string).
The outer parens on the filter are optional. The search base
defaults to the base slot-value of the ldap-object. This method
returns T or NIL, indicating results pending or not, respectively.
</dd>
<dt>
<span class="term"><b>next-search-result</b> <i>ldap-object</i></span>
<span class="type">[method]</span>
</dt>
<br class="both" /> <dd>After an ldap:search is executed, this
method can be used to return each of the entry objects that search
resulted in. next-search-result will return NIL if no more
results are available.
</dd>
<dt>
<span class="term"><b>dosearch</b> <i>var search-form &body
body</i></span> <span class="type">[macro]</span>
</dt>
<br class="both" /> <dd>Execute the ldap:search provided as
<code>search-form</code> and iterate through the results binding
each resulting entry object to <code>var</code> before evaluating
<code>body.</code> Returns the number of entries processed.
<b>NB: </b>If the body of the loop involves LDAP transactions it
is probably best that a difference LDAP instance be employed.
</dd>
<dt>
<span class="term"><b>ldif-search</b> <i>&rest
ldap-search-args</i></span> <span class="type">[macro]</span>
</dt>
<br class="both" /> <dd>Prints the results of a search in LDIF.
This macro is probably most useful in an interactive setting.
<code>ldap-search-args</code> are passed directly to the search
method described above.
</dd>
</dl>
<hr>
<address><a href="mailto:montuori@gmail.com">kevin montuori</a></address>
<!-- Created: Sun Jan 22 14:36:42 EST 2006 -->
<!-- hhmts start -->
Last modified: Sat Jan 13 09:01:44 EST 2007
<!-- hhmts end -->
</body>
</html>
Jump to Line
Something went wrong with that request. Please try again.