initial import of docbook contribution from Sun

git-svn-id: svn://10.0.0.236/trunk@228382 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
richm%stanfordalumni.org
2007-06-20 14:26:52 +00:00
parent 098dcde100
commit dd758b072f
57 changed files with 48324 additions and 0 deletions

View File

@@ -0,0 +1,24 @@
The split here is Directory SDK for C versus Directory SDK for Java.
The content is the very latest I have... but I have been tardy in reading
the developer Wiki, so perhaps some of what I've done is out of sync. I mean
Anton has reviewed the C SDK content and I've updated that to account for
his review comments. Also, I added what was necessary to cover the new
sample code I wrote (and I think Anton checked in). But it might not do
blindly to overwrite anything on the Wiki with what I have here. And it
might require a little post-update Wiki gardening to remove weeds.
The Directory SDK for C guide includes reference material. The Directory SDK
for Java guide does not, since there should be Javadoc somewhere. If this
assumption is wrong, let me know. I had a script to do that in my home dir
at work.
This version has the proper license as per
https://bugzilla.mozilla.org/show_bug.cgi?id=369156
The top files for each book are named 00-Programmers-Guide.book, so all
the other files are then pulled in through SYSTEM entities. In other words
run validation on the .books.
Hope it helps,
mark.craig@gmail.com, June 19, 2007

View File

@@ -0,0 +1,114 @@
<!--
Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
Portions copyright 1999 Netscape Communications Corporation. All
Rights Reserved.
The contents of this document are subject to the terms of the
Creative Commons Attribution-ShareAlike 2.5 license or any later
version (the "License"). You may not use this document except in
compliance with the License.
See the License for the specific language governing
permissions and limitations under the License. You can obtain
a copy of the License at
http://creativecommons.org/licenses/by-sa/2.5/legalcode.
-->
<!DOCTYPE BOOK PUBLIC "-//OASIS//DTD DocBook V4.3//EN" [
<!ENTITY BookTitle "Programmer's Guide">
<!ENTITY DirectorySDKForC "Directory SDK for C">
<!ENTITY DirectorySDKForJava "Directory SDK for Java">
<!ENTITY abstract SYSTEM "abstract.sgm">
<!ENTITY best-practices SYSTEM "best-practices.sgm">
<!ENTITY choose-api SYSTEM "choose-api.sgm">
<!ENTITY cnDirectoryServer "Directory Server">
<!ENTITY csdk-api SYSTEM "csdk-api.sgm">
<!ENTITY csdk-client SYSTEM "csdk-client.sgm">
<!ENTITY csdk-compare SYSTEM "csdk-compare.sgm">
<!ENTITY csdk-controls SYSTEM "csdk-controls.sgm">
<!ENTITY csdk-datatypes SYSTEM "csdk-datatypes.sgm">
<!ENTITY csdk-extendop SYSTEM "csdk-extendop.sgm">
<!ENTITY csdk-filter-conf SYSTEM "csdk-filter-conf.sgm">
<!ENTITY csdk-functions SYSTEM "csdk-functions.sgm">
<!ENTITY csdk-ldap-urls SYSTEM "csdk-ldap-urls.sgm">
<!ENTITY csdk-multithread SYSTEM "csdk-multithread.sgm">
<!ENTITY csdk-quickstart SYSTEM "csdk-quickstart.sgm">
<!ENTITY csdk-resultcodes SYSTEM "csdk-resultcodes.sgm">
<!ENTITY csdk-sasl SYSTEM "csdk-sasl.sgm">
<!ENTITY csdk-search SYSTEM "csdk-search.sgm">
<!ENTITY csdk-server-info SYSTEM "csdk-server-info.sgm">
<!ENTITY csdk-ssl SYSTEM "csdk-ssl.sgm">
<!ENTITY csdk-understanding SYSTEM "csdk-understanding.sgm">
<!ENTITY csdk-whatsnew SYSTEM "csdk-whatsnew.sgm">
<!ENTITY csdk-write SYSTEM "csdk-write.sgm">
<!ENTITY hierovrw SYSTEM "figures/hierovrw.eps" NDATA eps>
<!ENTITY legal SYSTEM "legal.sgm">
<!ENTITY license SYSTEM "license.txt">
<!ENTITY preface SYSTEM "preface.sgm">
<!ENTITY understanding-ldap SYSTEM "understanding-ldap.sgm">
<!NOTATION graphic SYSTEM "graphic">
]>
<book lang="en">
<title>LDAP C SDK Programmer's Guide</title>
<bookinfo>
<authorgroup><author><firstname>Mark</firstname><surname>Craig</surname>
</author></authorgroup>
<pubdate>June 2007</pubdate>
<publisher>
<publishername>Sun Microsystems, Inc.</publishername>
<address>
<street>4150 Network Circle</street>
<city>Santa Clara</city><state>CA</state><postcode>95054</postcode>
<country>U.S.A.</country>
</address></publisher>
<copyright><year>2000-2007</year><holder>Sun Microsystems, Inc. All Rights Reserved.</holder></copyright>
<legalnotice><para><emphasis role="strong">License</emphasis> -
<emphasis>The contents of this document are subject to the terms of
the Creative Commons Attribution-ShareAlike 2.5 license or any later version (the
"License"). You may not use this document except in compliance with
the License.</emphasis></para>
<para><emphasis>See the License for the specific language governing
permissions and limitations under the License. The full text of the
License is provided at the end of this
document.</emphasis></para>&legal;
</legalnotice>
<abstract>&abstract;
</abstract>
</bookinfo>&preface;
&understanding-ldap;
&choose-api;
&best-practices;
&csdk-understanding;
&csdk-quickstart;
&csdk-whatsnew;
&csdk-client;
&csdk-api;
&csdk-search;
&csdk-filter-conf;
&csdk-write;
&csdk-compare;
&csdk-ldap-urls;
&csdk-server-info;
&csdk-ssl;
&csdk-controls;
&csdk-sasl;
&csdk-extendop;
&csdk-multithread;
&csdk-datatypes;
&csdk-functions;
&csdk-resultcodes;
<appendix id="share-alike">
<title>Creative Commons Attribution-ShareAlike 2.5</title>
<para>The contents of this document are subject to the terms of the
Creative Commons Attribution-ShareAlike 2.5 license (the
"License"). You may not use this document except in compliance with
the License.</para>
<para>See the License for the specific language governing permissions
and limitations under the License. The full text of the License is as
follows.</para>
<programlisting>&license;</programlisting>
</appendix>
<index><title>Index</title>
<indexentry><primaryie></primaryie></indexentry></index>
</book>

View File

@@ -0,0 +1,20 @@
<!--
Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
Portions copyright 1999 Netscape Communications Corporation. All
Rights Reserved.
The contents of this document are subject to the terms of the
Creative Commons Attribution-ShareAlike 2.5 license or any later
version (the "License"). You may not use this document except in
compliance with the License.
See the License for the specific language governing
permissions and limitations under the License. You can obtain
a copy of the License at
http://creativecommons.org/licenses/by-sa/2.5/legalcode.
-->
<para>This <citetitle>&BookTitle;</citetitle> shows you how to
create LDAP client applications in the C language to connect to LDAP servers.
This guide also shows you how to perform standard LDAP operations.</para>

View File

@@ -0,0 +1,378 @@
<!--
Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
Portions copyright 1999 Netscape Communications Corporation. All
Rights Reserved.
The contents of this document are subject to the terms of the
Creative Commons Attribution-ShareAlike 2.5 license or any later
version (the "License"). You may not use this document except in
compliance with the License.
See the License for the specific language governing
permissions and limitations under the License. You can obtain
a copy of the License at
http://creativecommons.org/licenses/by-sa/2.5/legalcode.
-->
<chapter id="best-practices-overview"><title>Best Practices for
Writing Client Applications</title>
<highlights>
<itemizedlist>
<para>This chapter includes best practices for developing client applications
and cover the following topics:</para>
<listitem><para><olink targetptr="best-ldapv3">Creating Your Application</olink></para>
</listitem>
<listitem><para><olink targetptr="best-troubleshooting">Troubleshooting Problems</olink></para>
</listitem>
</itemizedlist>
</highlights>
<sect1 id="best-ldapv3"><title>Creating Your Application</title>
<itemizedlist>
<para>This section identifies practices to observe when creating directory
client applications.</para>
<listitem><para><olink targetptr="specify-ldapv3">Specify LDAP v3</olink></para>
</listitem>
<listitem><para><olink targetptr="best-authenticating">Authenticate Correctly</olink></para>
</listitem>
<listitem><para><olink targetptr="best-connect">Limit Connection Overhead</olink></para>
</listitem>
<listitem><para><olink targetptr="best-inactivity-timeouts">Handle Potential
Inactivity Timeouts</olink></para></listitem>
<listitem><para><olink targetptr="best-entries">Retrieve Entries Intelligently</olink></para>
</listitem>
<listitem><para><olink targetptr="best-filters">Write Simple, Conforming LDAP
Filters</olink></para></listitem>
<listitem><para><olink targetptr="best-mods">Performing Specific Modifications</olink></para>
</listitem>
<listitem><para><olink targetptr="best-rc">Trust Result Codes</olink></para>
</listitem>
<listitem><para><olink targetptr="best-groups">Limit Dealings With Groups
and Roles</olink></para></listitem>
<listitem><para><olink targetptr="best-dse">Read the DSE</olink></para>
</listitem>
<listitem><para><olink targetptr="best-resources">Use Resource-Intensive Features Sparingly</olink></para></listitem>
<listitem><para><olink targetptr="best-dit">Avoid Hard Coding Certain Information
</olink></para></listitem>
<listitem><para><olink targetptr="best-schema">Define Schemas Only When Necessary
</olink></para></listitem>
<listitem><para><olink targetptr="best-refer">Handle Referrals</olink></para>
</listitem>
<listitem><para><olink targetptr="best-not-rdbm">Treat a Directory as a Directory
</olink></para></listitem>
</itemizedlist>
<sect2 id="specify-ldapv3"><title>Specify LDAP v3</title>
<itemizedlist>
<para>Many client libraries default to LDAP v2, but you can elect to use LDAP
v3. To benefit from LDAP v3 features, you can set up the connection, and then
authenticate explicitly using LDAP v3.</para>
<listitem><para>With JNDI, you could use LDAP v3 as shown here.</para>
<programlisting role="fragment">import java.util.Hashtable;
import javax.naming.ldap.InitialLdapContext;
Hashtable env = new Hashtable();
env.put("java.naming.ldap.version", "<emphasis>3</emphasis>");
InitialLdapContext ctx = new InitialLdapContext(env, null);</programlisting>
</listitem>
<listitem><para>With &DirectorySDKForC;, you could use LDAP v3 as shown
here.</para>
<programlisting role="fragment">#include "ldap.h"
int version = <emphasis>LDAP_VERSION3</emphasis>;
ldap_set_option( NULL, LDAP_OPT_PROTOCOL_VERSION, &amp;version );</programlisting>
<para>&DirectorySDKForC; uses LDAP v3 by default.</para></listitem>
<listitem><para>With &DirectorySDKForJava;, you could use LDAP v3 as shown
here.</para>
<programlisting role="fragment">import netscape.ldap.LDAPConnection;
LDAPConnection ld = new LDAPConnection();
ld.setOption(LDAPv3.PROTOCOL_VERSION, new Integer(<emphasis>3</emphasis>));
</programlisting>
</listitem>
</itemizedlist>
</sect2>
<sect2 id="best-authenticating"><title>Authenticate Correctly</title>
<para>Your SDK uses terminology that is slightly different from LDAP v3. In
LDAP v3, you connect, then you bind and perform LDAP operations, then you
unbind and disconnect. The bind is the authentication operation in LDAP. Your
application can hold onto a connection but change the authentication credentials
by using the bind operation again.</para>
<para>Some directories do not allow anonymous access, even for reads. When
you build your application, keep the option that allows users to authenticate
to the directory. Furthermore, the information sent across the network can
be sensitive. You can protect sensitive data by allowing the application to
secure the connection by using Secure Sockets Layer (SSL) or Start Transport
Layer Security (TLS).</para>
<para>If your application needs to authenticate, obtain a regular account
to authenticate with the directory, rather than using the directory superuser
account such as <literal>cn=Directory Manager</literal>. When you authenticate
as directory superuser, you often bypass normal access control mechanisms.
Bypassing normal access control renders auditing directory access more difficult.
</para>
<para>When authenticating, have your application use SSL or SASL DIGEST MD5
to avoid sending passwords over the network in clear text. Furthermore, when
using password-based authentication, have your application check password
policy controls, especially to determine when a password must be renewed.</para>
</sect2>
<sect2 id="best-connect"><title>Limit Connection Overhead</title>
<para>A new connection requires system resources. The LDAP model allows you
to reuse connections by binding again with a different identity on the same
connection. Thus, you can avoid the costs of new connections, particularly
negotiated connections such as connections that use SSL, by reusing connections.
Your application can use a pool of connections, rebinding when necessary.
Your application can alternatively use the proxy authorization control to
remain authenticated as the application but perform operations on behalf of
a particular user.</para>
<para>When establishing a connection, your application can provide alternate
server host names and port numbers to facilitate failover that is transparent
to the application. You can also set time limits for LDAP operations to avoid
getting blocked.</para>
<para>When finished with a connection, your application should perform an
unbind.</para></sect2>
<sect2 id="best-inactivity-timeouts"><title>Handle Potential Inactivity Timeouts</title>
<para>Most network equipment can use timeouts to drop stale connections, ensuring
the equipment keeps a maximum number of connections that are available.</para>
<para>If your application pools connections or opens connections for persistent
search, than guard against timeouts that drop those connections. Use the connections
occasionally to reset inactivity timers present in the network.</para>
<para>Alternatively, if you have control over the connection, consider disabling
inactivity time outs for your applications that need to keep persistent connections
open. Load balancers and proxy software often use inactivity timeouts.</para>
</sect2>
<sect2 id="best-entries"><title>Retrieve Entries Intelligently</title>
<para>&cnDirectoryServer; typically responds quickly to requests for entries.
Yet, &cnDirectoryServer; can respond most quickly when your application asks
it to do only necessary work. If you need to read only a few attributes in
an entry, request each attribute explicitly. Avoid reading the entire entry,
then parsing the entire entry to obtain the required data.</para>
<para>Furthermore, when you do request attributes in an entry, retrieve all
the required attributes at once. Each new request involves a new operation
on the server.</para>
<para>If any of the attributes that you require are operational attributes,
you must request those attributes specifically. Such attributes are identifiable
in directory schema by their <literal>USAGE</literal>, which is <literal>directoryOperation
</literal> or <literal>dsaOperation</literal>.</para>
<para>When retrieving entries and attributes, recognize that you might not
have access to all the attributes that exist.</para></sect2>
<sect2 id="best-filters"><title>Write Simple, Conforming LDAP Filters</title>
<indexterm>
<primary>LDAP filters</primary>
<secondary>writing</secondary>
</indexterm>
<para>The best filters use attributes that are indexed according to the way
the attributes are indexed. For example, if <literal>employeeNumber</literal> is
indexed for equality, your filter should be an equality filter such as <literal>(employeeNumber=123456)
</literal>. Do not use a substring filter instead.</para>
<para>Avoid deeply nested complex filters when you can. When you must use
complex filters, place the most specific filters first to narrow the list
of candidate entries the directory must check. For best results, use <literal>not
</literal>, <literal>!</literal>, only with <literal>and</literal>, <literal>&amp;
</literal>, for example <literal>(&amp;(cn=Barbara)(!(sn=Jensen)))</literal>.
When you use <literal>not</literal> with <literal>or</literal> in a filter,
the directory must construct a candidate list of everything except what your
filter specifies.</para></sect2>
<sect2 id="best-mods"><title>Performing Specific Modifications</title>
<para>Modifications are atomic on the entry to which the modifications apply.
When modifying multivalued attributes, delete and replace specific values.
Do not replace an entire list of multiple values to change only a few values.
Replacing specific values is particularly good practice when the changes must
be replicated across a set of servers.</para>
<para>Moreover, when you have large values to store in an attribute, store
a reference to the data instead of storing the data object.</para></sect2>
<sect2 id="best-rc"><title>Trust Result Codes</title>
<indexterm>
<primary>result codes</primary>
<secondary>trust</secondary>
</indexterm>
<para>&cnDirectoryServer; trades tight consistency across replica servers
for very high performance, availability, and scalability. By allowing <firstterm>
loose consistency</firstterm> of data across sets of replica servers, &cnDirectoryServer; instances
can respond very quickly to your application. Yet, data replication is not
instantaneous. A short but detectable delay can ensue after a server returns
success for a write operation, but before the effects are seen on other replicas.
</para>
<para>Therefore, when your application receives a result code from &cnDirectoryServer; to
indicate that an operation was successful, your application should trust the
result code. When application requests are balanced across replicas, reading
from another replica might result in errors due to a slight delay in replication.
</para></sect2>
<sect2 id="best-groups"><title>Limit Dealings With Groups and Roles</title>
<indexterm>
<primary>groups</primary>
<secondary>working with</secondary>
</indexterm>
<para>When you want to know whether an account belongs to a group or a role,
read only the necessary attribute values. Do not read the entire list of group
members.</para>
<orderedlist>
<para>For <literal>dynamic groups</literal>, do the following:</para>
<listitem><para>Read the URL from the group definition.</para></listitem>
<listitem><para>Examine the host, DN, and scope of the URL.</para></listitem>
<listitem><para>Apply the filter part of the URL to the entry for the account.</para>
</listitem>
</orderedlist>
<para><indexterm>
<primary>roles</primary>
<secondary>working with</secondary>
</indexterm>For <literal>roles</literal>, compare the DN of the role to the <literal>
nsRole</literal> attribute of the entry for the account, such as <literal>(nsrole=cn=management,ou=people,dc=example,dc=com)
</literal>. You can then retrieve all the values of the <literal>nsRole</literal> attribute
for the account.</para></sect2>
<sect2 id="best-dse"><title>Read the DSE</title>
<indexterm>
<primary>DSE, root</primary>
<secondary>reading</secondary>
</indexterm>
<para>The root DSE is the entry that is retrieved by <command>ldapsearch -b
"" -s base "(objectclass=*)"</command>. The root DSE describes server capabilities.
The root DSE contains information about supported LDAP protocol versions,
naming contexts (suffixes), LDAP v3 controls, LDAP v3 extensions, and authentication
mechanisms. The root DSE can contain information about the server version.</para>
<para>Some directory administrators protect access to the root DSE. Yet, applications
might read the root DSE to confirm that the server in fact supports functionality
required by applications.</para></sect2>
<sect2 id="best-resources"><title>Use Resource-Intensive Features Sparingly</title>
<para>Directories offer powerful features that can nevertheless place a heavy
load on the server. Two such features are persistent search, and server-side
sorting.</para>
<para>Persistent search lets you start a search that does not stop when complete,
but instead allows you to receive updates when entries are modified. To provide
this feature, the server must handle your search when anything happens to
an entry in its scope.</para>
<para>Server-side sorting requires that the server sort the entries that are
returned during a search. Instead of returning entries as quickly as possible,
the server must therefore get the list to return, and sort the list.</para>
</sect2>
<sect2 id="best-dit"><title>Avoid Hard Coding Certain Information</title>
<para>The container entry for a subtree might be not be identical on different
directories. Rather than hard code the container entry throughout your application,
locate the container entry. Then navigate beneath the container entry in the
tree.</para>
<para>Object classes and attribute types for the same information can also
differ from directory to directory. Use configuration files, properties files,
or other easily modifiable variables rather than hard coding object class
and attribute type identifiers into your application.</para>
<para>Be aware as well that object class and attribute type identifiers are <emphasis>
not case-sensitive</emphasis> in LDAP. Your application should therefore recognize
that <literal>inetOrgPerson</literal> and <literal>inetorgperson</literal> are
equivalent, as are <literal>isMemberOf</literal> and <literal>ismemberof</literal>.
</para></sect2>
<sect2 id="best-schema"><title>Define Schemas Only When Necessary</title>
<indexterm>
<primary>schema</primary>
<secondary>defining</secondary>
</indexterm>
<para>Schemas define the object classes and attribute types that are recognized
by the directory. If your application can use a standard schema, use the standard
schema. &cnDirectoryServer; contains schemas that define numerous standard
object classes, and attribute types.</para>
<itemizedlist>
<para>When you must define your own schema objects, follow these guidelines:</para>
<listitem><para>Extend existing object classes by using <literal>AUXILIARY</literal> classes.
</para></listitem>
<listitem><para>Create new attributes rather than redefining existing attributes.
</para><para>Other applications might depend on existing attributes to keep
their existing semantics.</para></listitem>
<listitem><para>Obtain new object identifiers for the schema elements you
define, rather than reusing existing object identifiers.</para></listitem>
<listitem><para>Obtain new names for the schema elements you define, rather
than reusing existing names.</para></listitem>
<listitem><para>Update &cnDirectoryServer; schema over LDAP if you can.</para>
</listitem>
</itemizedlist>
</sect2>
<sect2 id="best-refer"><title>Handle Referrals</title>
<indexterm>
<primary>referrals</primary>
<secondary>following</secondary>
</indexterm>
<para>LDAP v3 allows directories that are unable to handle your request to
refer your application to other directories. Your application should follow
those referrals.</para>
<para>When following referrals, realize that authentication procedures might
not be exactly the same on different directories. Also, directories that refer
to each other could potentially cause a referral loop. With &DirectorySDKForC; and &DirectorySDKForJava;,
you can limit referral hops to prevent your application from being referred
endlessly from one directory to another directory. The JNDI interface enables
you to follow referrals automatically.</para></sect2>
<sect2 id="best-not-rdbm"><title>Treat a Directory as a Directory</title>
<para>A directory is typically a repository for identity data, and for information
that you expect to keep for awhile and read often. You might typically find
relational databases better adapted to hold transient data such as session
keys and presence information, or voluminous accumulated data such as application
logs.</para></sect2>
</sect1>
<sect1 id="best-troubleshooting"><title>Troubleshooting Problems</title>
<para>This section covers basic troubleshooting approaches and techniques
to use when developing directory client applications. You can check result
codes, check server log files, and inspect network packets.</para>
<sect2 id="trouble-rc"><title>Check Result Codes</title>
<indexterm>
<primary>troubleshooting</primary>
<secondary>result codes</secondary>
</indexterm>
<para>When an LDAP request from your application fails on the server, the
server sends back a result code, and possibly an explanatory message. Your
application should check the result codes, and for explanatory messages. Common
failure result codes include the following, which are expressed as decimal
values. Others result codes are defined as well.</para>
<variablelist>
<varlistentry><term><errorcode>1</errorcode></term>
<listitem><para>LDAP operations error. The server encountered an error while
processing your request.</para>
</listitem>
</varlistentry>
<varlistentry><term><errorcode>32</errorcode></term>
<listitem><para>No such object. The entry is not present on the server. Also,
no referral is defined for the entry.</para>
</listitem>
</varlistentry>
<varlistentry><term><errorcode>49</errorcode></term>
<listitem><para>Invalid credentials. Your application failed to authenticate
properly.</para>
</listitem>
</varlistentry>
<varlistentry><term><errorcode>53</errorcode></term>
<listitem><para>LDAP unwilling to perform. The directory does not support
the request. Alternatively, the directory is not currently in a state in which
to complete your request. For example, the directory might be in read-only
mode when your application requests a modification.</para>
</listitem>
</varlistentry>
<varlistentry><term><errorcode>65</errorcode></term>
<listitem><para>Object class violation. Your write request would cause an
entry to no longer conform to the schema defined for the directory.</para>
</listitem>
</varlistentry>
<varlistentry><term><errorcode>68</errorcode></term>
<listitem><para>Already exists. Your application is requesting to add an entry
that has the same DN as an entry already present in the directory.</para>
</listitem>
</varlistentry>
</variablelist>
<para><ulink url="http://ietf.org/rfc/rfc4511.txt" type="text_url">RFC 4511</ulink> defines
LDAP error codes, as does <olink targetptr="bdaxx">Chapter&nbsp;22, Directory
SDK for C Result Codes</olink>.</para></sect2>
<sect2 id="trouble-logs"><title>Check Server Log Files</title>
<indexterm>
<primary>troubleshooting</primary>
<secondary>log files</secondary>
</indexterm>
<para>&cnDirectoryServer; logs messages related to server operation in its <filename>
logs/errors</filename> file. If you have access to this file, you might find
useful troubleshooting information there.</para>
<para>When debugging your application against &cnDirectoryServer;, you can
adjust the log level, as well. See the server documentation for instructions.</para>
</sect2>
<sect2 id="trouble-network-tools"><title>Inspect Network Packets</title>
<indexterm>
<primary>troubleshooting</primary>
<secondary>decoding packets</secondary>
</indexterm>
<para>Although LDAP is not a textual protocol, tools such as <citerefentry>
<refentrytitle>snoop</refentrytitle><manvolnum>1M</manvolnum></citerefentry>, <command>
ethereal</command>, and <command>tcpdump</command> can decode the packets,
sometimes providing you with important debugging information.</para></sect2>
</sect1>
</chapter>

View File

@@ -0,0 +1,98 @@
<!--
Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
Portions copyright 1999 Netscape Communications Corporation. All
Rights Reserved.
The contents of this document are subject to the terms of the
Creative Commons Attribution-ShareAlike 2.5 license or any later
version (the "License"). You may not use this document except in
compliance with the License.
See the License for the specific language governing
permissions and limitations under the License. You can obtain
a copy of the License at
http://creativecommons.org/licenses/by-sa/2.5/legalcode.
-->
<chapter id="best-practices-choose"><title>Choosing a Client
SDK</title>
<highlights>
<para>This chapter discusses software development kits to help you select
the appropriate directory SDK for your particular situation.</para>
<itemizedlist>
<para>This chapter covers the following topics:</para>
<listitem><para><olink targetptr="choose-jndi">Java Naming and Directory Interface
</olink></para></listitem>
<listitem><para><olink targetptr="choose-ljdk">Directory SDK for Java</olink></para>
</listitem>
<listitem><para><olink targetptr="choose-cdsk">Directory SDK for C</olink></para>
</listitem>
<listitem><para><olink targetptr="choose-solaris-libldap">Operating System libldap Library</olink></para></listitem>
<listitem><para><olink targetptr="choose-other">Support for Other Programming
Languages</olink></para></listitem>
</itemizedlist>
</highlights>
<sect1 id="choose-jndi"><title>Java Naming and Directory Interface</title>
<indexterm>
<primary>Java Naming and Directory Interface</primary>
</indexterm><indexterm>
<primary>JNDI</primary>
<see>Java Naming and Directory Interface</see></indexterm>
<para>Java Naming and Directory Interface (JNDI) technology supports directory
access through LDAP and DSML v2 from <trademark>Java</trademark> applications,
and is part of the Java platform. With JNDI, you can build powerful, portable,
directory-enabled applications that do not depend on classes outside the Java
platform.</para>
<para>JNDI provides an abstract model that lets you access not only directories,
but also naming services in general, including DNS, RMI, COS, and file systems.</para>
<para>For information about JNDI, see <ulink
url="http://java.sun.com/products/jndi/" type="url"></ulink>. The <citetitle>JNDI
Tutorial</citetitle> contains descriptions and examples of how to use JNDI.
The tutorial is at <ulink url="http://java.sun.com/products/jndi/tutorial/"
type="url"></ulink>.</para></sect1>
<sect1 id="choose-cdsk"><title>&DirectorySDKForC;</title>
<para>&DirectorySDKForC; lets you access LDAP directories from C and C++
applications. &DirectorySDKForC; applications depend on &DirectorySDKForC; libraries,
which are available on a wide range of platforms.</para>
<para>&DirectorySDKForC; was the subject of Internet-Draft work but never
became a standard API. &DirectorySDKForC; closely follows LDAP v3, providing
support for core LDAP operations and for LDAP v3 extensions and widely used
controls. &DirectorySDKForC; offers a rich API to the C and C++ developer
familiar with the LDAP model. &cnDirectoryServer; relies on &DirectorySDKForC;.
</para>
<para>This document demonstrates how to use &DirectorySDKForC;. &DirectorySDKForC; code
is published in open source form as part of the Mozilla Directory SDK project.</para>
</sect1>
<sect1 id="choose-ljdk"><title>&DirectorySDKForJava;</title>
<para>&DirectorySDKForJava; lets you access LDAP directories from Java
applications, but it is not part of the Java platform.</para>
<para>Although not a standard API, &DirectorySDKForJava; closely follows
LDAP v3 idioms. &DirectorySDKForJava; provides a rich set of interfaces
to the Java developer familiar with the LDAP model.</para>
<para>This document demonstrates how to use &DirectorySDKForJava;. &DirectorySDKForJava; code
is published in open source form as part of the Mozilla Directory SDK project.</para>
</sect1>
<sect1 id="choose-solaris-libldap"><title>Operating System <filename>libldap</filename> Library
</title>
<indexterm>
<primary>libraries</primary>
<secondary><filename>libldap</filename></secondary>
</indexterm><indexterm>
<primary><filename>libldap</filename></primary>
</indexterm>
<para>The native LDAP library on <trademark>Solaris</trademark> systems provides
essentially the same API as &DirectorySDKForC;. Many &DirectorySDKForC; need
only be recompiled to work with <filename>libldap</filename>.</para>
<para>The LDAP library is sometimes not compatible with <filename>libldap</filename> on
many GNU/Linux distributions. Many GNU/Linux distributions provide OpenLDAP
support by default.</para></sect1>
<sect1 id="choose-other"><title>Support for Other Programming Languages</title>
<para>Support for directory access is available in a number of contexts where
you do not choose to use the C or Java languages.</para>
<para>For example, Perl has the PerLDAP module and the Net::LDAP collection
of modules. Python has the <literal>python-ldap</literal> package. PHP can
be compiled with LDAP support. Ruby has the Ruby/LDAP extension module. In
many cases, you can choose the language that fits the task and find that LDAP
support is available.</para></sect1>
</chapter>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,768 @@
<!--
Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
Portions copyright 1999 Netscape Communications Corporation. All
Rights Reserved.
The contents of this document are subject to the terms of the
Creative Commons Attribution-ShareAlike 2.5 license or any later
version (the "License"). You may not use this document except in
compliance with the License.
See the License for the specific language governing
permissions and limitations under the License. You can obtain
a copy of the License at
http://creativecommons.org/licenses/by-sa/2.5/legalcode.
-->
<chapter id="csdk-client"><title>Writing an LDAP Client With &DirectorySDKForC;</title>
<highlights>
<para>With &DirectorySDKForC;, you can write a new application. You can
also enable an existing application to interact with a Lightweight Directory
Access Protocol (LDAP) server. This chapter explains how to connect to an
LDAP server, authenticate, request operations, and disconnect from the server.</para>
<itemizedlist>
<para>This chapter covers the following topics:</para>
<listitem><para><olink targetptr="bdacb">Designing an LDAP Client With Directory
SDK for C</olink></para></listitem>
<listitem><para><olink targetptr="bdacc">Initializing an LDAP Session With
Directory SDK for C</olink></para></listitem>
<listitem><para><olink targetptr="bdacj">Binding and Authenticating to an
LDAP Server With Directory SDK for C</olink></para></listitem>
<listitem><para><olink targetptr="bdacs">Performing LDAP Operations With Directory
SDK for C</olink></para></listitem>
<listitem><para><olink targetptr="bdact">Closing the Connection to an LDAP
Server With Directory SDK for C</olink></para></listitem>
</itemizedlist>
</highlights>
<sect1 id="bdacb"><title>Designing an LDAP Client With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>designing LDAP client</secondary>
</indexterm><indexterm>
<primary>LDAP clients</primary>
<secondary>designing with C SDK</secondary>
</indexterm>
<para>The following procedure outlines a typical process for communicating
with an LDAP server.</para>
<task><title>To Communicate With an LDAP Server</title>
<procedure>
<step><para>Initialize an LDAP session.</para><para>See <olink targetptr="bdacc">
Initializing an LDAP Session With Directory SDK for C</olink> for details.</para>
</step>
<step><para>Bind to the LDAP server, if necessary.</para><para>See <olink targetptr="bdacj">Binding and Authenticating to an LDAP Server With Directory
SDK for C</olink> for details.</para></step>
<step><para>Perform LDAP operations, such as searching the directory or modifying
entries in the directory.</para><para>See <olink targetptr="bdacs">Performing
LDAP Operations With Directory SDK for C</olink> for details.</para></step>
<step><para>Close the connection to the LDAP server when finished.</para><para>See <olink targetptr="bdact">Closing the Connection to an LDAP Server With Directory
SDK for C</olink> for details.</para></step>
</procedure>
<example id="csdk-search-example">
<title>Performing an LDAP Search</title>
<indexterm>
<primary>example programs</primary>
<secondary>LDAP search</secondary>
</indexterm>
<para>This sample source code shows a client that requests an LDAP search
operation from a server. The LDAP server runs on the local system on port <literal>
389</literal>. The client searches the directory for entries with the last
name <literal>Jensen</literal> (<literal>sn=Jensen</literal>), and prints
the distinguished name (DN) of any matching entry.</para>
<programlisting>#include &lt;stdio.h>
#include "ldap.h"
/* Specify the search criteria here. */
#define HOSTNAME "localhost"
#define PORTNUMBER 389
#define BASEDN "dc=example,dc=com"
#define SCOPE LDAP_SCOPE_SUBTREE
#define FILTER "(sn=Jensen)"
int
main( int argc, char **argv )
{
LDAP *ld;
LDAPMessage *result, *e;
char *dn;
int version, rc;
/* Print out an informational message. */
printf( "Connecting to host %s at port %d...\n\n", HOSTNAME,
PORTNUMBER );
/* STEP 1: Get a handle to an LDAP connection and
set any session preferences. Use prldap_init() for IPv6. */
if ( (ld = ldap_init( HOSTNAME, PORTNUMBER )) == NULL ) {
perror( "ldap_init" );
return( 1 );
}
/* Use the LDAP_OPT_PROTOCOL_VERSION session preference to specify
that the client is an LDAPv3 client. */
version = LDAP_VERSION3;
ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &amp;version );
/* STEP 2: Bind to the server.
In this example, the client binds anonymously to the server
(no DN or credentials are specified). */
rc = ldap_simple_bind_s( ld, NULL, NULL );
if ( rc != LDAP_SUCCESS ) {
fprintf(stderr, "ldap_simple_bind_s: %s\n", ldap_err2string(rc));
return( 1 );
}
/* Print out an informational message. */
printf( "Searching the directory for entries\n"
" starting from the base DN %s\n"
" within the scope %d\n"
" matching the search filter %s...\n\n",
BASEDN, SCOPE, FILTER );
/* STEP 3: Perform the LDAP operations.
In this example, a simple search operation is performed.
The client iterates through each of the entries returned and
prints out the DN of each entry. */
rc = ldap_search_ext_s( ld, BASEDN, SCOPE, FILTER, NULL, 0,
NULL, NULL, NULL, 0, &amp;result );
if ( rc != LDAP_SUCCESS ) {
fprintf(stderr, "ldap_search_ext_s: %s\n", ldap_err2string(rc));
return( 1 );
}
for ( e = ldap_first_entry( ld, result ); e != NULL;
e = ldap_next_entry( ld, e ) ) {
if ( (dn = ldap_get_dn( ld, e )) != NULL ) {
printf( "dn: %s\n", dn );
ldap_memfree( dn );
}
}
ldap_msgfree( result );
/* STEP 4: Disconnect from the server. */
ldap_unbind( ld );
return( 0 );
}
...</programlisting>
</example>
</task>
</sect1>
<sect1 id="bdacc"><title>Initializing an LDAP Session With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>initializing an LDAP session</secondary>
</indexterm><indexterm>
<primary>LDAP session</primary>
<secondary>initializing</secondary>
</indexterm>
<para>Before connecting to an LDAP server, you must initialize a session.
As part of this process, you create an <structname>LDAP</structname> structure
that contains information about the LDAP server and session. You then pass
this <structname>LDAP</structname> structure, usually as a pointer, to all
subsequent functions in order to identify the LDAP server with which you are
working. Sample code for initializing an LDAP session is provided in <olink targetptr="bdacf">Example Session Initialization</olink>.</para>
<note><para>If you plan to connect to the LDAP server over the Secure Sockets
Layer (SSL) protocol, the procedure for initializing an LDAP session is different.
For details, see <olink targetptr="csdk-ssl">Chapter&nbsp;15, SSL Connections
With Directory SDK for C</olink>.</para></note>
<sect2 id="bdacd"><title>Specifying a Single LDAP Server</title>
<para>To initialize an LDAP session, call <function>ldap_init</function>,
or <function>prldap_init</function> for IPv6 support, with the host name and
port number of the LDAP server. If the server is using the default port <literal>
389</literal> for the LDAP server, pass <literal>LDAP_PORT</literal> as the
value for the <parameter>defport</parameter> parameter as shown here.</para>
<example id="csdk-init-example"><title>Passing an LDAP Server With the Default
LDAP Port</title>
<programlisting>...
LDAP *ld
...
ld = ldap_init( "directory.example.com", LDAP_PORT );</programlisting>
</example>
<para>If successful, <function>ldap_init</function>, or <function>prldap_init</function>,
returns a connection handle to the LDAP server. A <firstterm>connection handle</firstterm> is
a pointer to the <structname>LDAP</structname> structure that contains information
about the connection. You must pass this pointer to the API for connecting,
authenticating, and performing LDAP operations on a server. For example, when
you search the directory, you pass the connection handle as a parameter to
provide a context for the connection.</para>
<note><para>The initialization function does not open a connection to the
LDAP server. The actual opening of a connection occurs when the first operation
is attempted.</para></note>
</sect2>
<sect2 id="bdace"><title>Specifying a List of LDAP Servers</title>
<para>When initializing the LDAP session, you can also specify a list of LDAP
servers for which you want to attempt connections. If the first LDAP server
in the list does not respond, the client attempts to connect to the next server
in the list. To specify a list of LDAP servers, pass a space-delimited list
of the host names as the first argument to the <function>ldap_init</function> or <function>
prldap_init</function> function. In the following example, the LDAP client
attempts to connect to the LDAP server on <literal>ld1.example.com</literal>,
port <literal>389</literal>. If that server does not respond, the client attempts
to connect to the LDAP server on <literal>ld2.example2.com</literal>, port <literal>
389</literal>. If that server does not respond, the client uses the server
on <literal>ld3.example.com</literal>, port <literal>389</literal>.</para>
<example id="csdk-init-mult-example"><title>Passing Multiple LDAP Servers
With the Default LDAP Port</title>
<programlisting>...
LDAP *ld
...
ld = ldap_init( "ld1.example.com ld2.example2.com
ld3.example.com", LDAP_PORT );</programlisting>
</example>
<para>If any servers do not use the default LDAP port, use the <replaceable>host</replaceable><literal>
:</literal><replaceable>port</replaceable> format to specify the server name
and port number. In the following example, that means <literal>ld1.example.com</literal>,
port <literal>389</literal>. If that server does not respond, the client attempts
to connect to the LDAP server on <literal>ld2.example.com</literal>, port <literal>
1389</literal>.</para>
<example id="csdk-init-mult2-example"><title>Passing Non-Default LDAP Ports</title>
<programlisting>...
LDAP *ld
...
ld = ldap_init( "ld1.example.com ld2.example.com:1389",
LDAP_PORT );</programlisting>
</example>
</sect2>
<sect2 id="bdacf"><title>Example Session Initialization</title>
<indexterm>
<primary>example programs</primary>
<secondary>initializing an LDAP session</secondary>
</indexterm>
<para>The following example initializes a session with an LDAP server, specifying
a list of LDAP servers to try: <literal>ldap.example.com:389</literal> and <literal>
directory.example.com:1389</literal>. The example also sets a session preference
that identifies the client as an LDAP v3 client. This session initialization
code uses the <function>prldap_init</function> function, which works on IPv6
networks. Notice that <function>prldap_init</function> does not connect to
the LDAP server right away.</para>
<para>After you initialize a session with an LDAP server, you can set session
preferences. For information, see<olink targetptr="bdacg">Setting Session
Preferences With Directory SDK for C</olink>. </para>
<example id="csdk-init2-example"><title>Initializing an LDAP Session</title>
<programlisting>#include &lt;stdio.h>
#include "ldappr.h"
#include "ldap.h"
...
LDAP *ld;
int ldap_default_port, version;
/* Specify list of LDAP servers that you want to try connecting to. */
char *ldap_host = "ldap.example.com directory.example.com:1389";
/* If the LDAP server is running on the standard LDAP port (port 389),
* you can use LDAP_PORT to identify the port number. */
ldap_default_port = LDAP_PORT;
...
/* Initialize the session with the LDAP servers. */
if ( ( ld = prldap_init( ldap_host, ldap_default_port, NULL ) ) == NULL ) {
perror( "prldap_init" );
return( 1 );
}
/* Specify the LDAP version supported by the client. */
version = LDAP_VERSION3;
ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &amp;version );
...
/* Subsequent calls pass ld as argument to identify the LDAP server. */
...</programlisting>
</example>
</sect2>
<sect2 id="bdacg"><title>Setting Session Preferences With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>setting LDAP session preferences</secondary>
</indexterm>
<para>With &DirectorySDKForC;, you can set preferences for your client
that you want applied to all LDAP sessions. To get or set the value of a preference,
call the <function>ldap_get_option</function> or <function>ldap_set_option</function> functions
respectively.</para>
<itemizedlist>
<para>Both functions pass two parameters in addition to the <parameter>ld</parameter> parameter,
which represents the connection to the server:</para>
<listitem><para>The <parameter>option</parameter> parameter identifies the
option that you want to get or set.</para></listitem>
<listitem><para>The <parameter>value</parameter> parameter is either a pointer
to a place to put the value to get, or a pointer to the value to set.</para>
</listitem>
</itemizedlist>
<para>You can set a preference for all connections by passing <literal>NULL</literal> as
the first argument, not an <structname>LDAP</structname> structure that specifies
the connection.</para>
<sect3 id="bdach"><title>Reconnecting Automatically</title>
<para>If communication with the LDAP server is interrupted, the server returns <errorcode>
LDAP_SERVER_DOWN</errorcode>. If you want your client to continue to attempt
communication with the server, you can set the <literal>LDAP_OPT_RECONNECT</literal> preference
for the session. Once set, if your connection is lost, the client attempts
another bind with the same authentication to reestablish the connection.</para>
<para>The following example shows that to set the reconnect preference, call
the <function>ldap_set_option</function> function and pass <literal>LDAP_OPT_RECONNECT
</literal> as the value of the <parameter>option</parameter> parameter. To
resume LDAP I/O operations automatically, set the <parameter>optdata</parameter> parameter
to <literal>LDAP_OPT_ON</literal>. This setting specifies the same connection
handle that can be used to reconnect to the server. </para>
<example><title>Passing Restart Preferences</title>
<programlisting>ldap_set_option( ld, LDAP_OPT_RECONNECT, LDAP_OPT_ON );</programlisting>
</example>
<para>To avoid resuming I/O operations, you would set the <parameter>optdata</parameter> parameter
to <literal>LDAP_OPT_OFF</literal>. This setting specifies that you want to
create a new connection handle to connect to the server. By default, the <parameter>
optdata</parameter> parameter is set to <literal>LDAP_OPT_OFF</literal>. Both <literal>
LDAP_OPT_OFF</literal> and <literal>LDAP_OPT_ON</literal> are cast to <literal>(void
*)</literal>.</para></sect3>
<sect3 id="bdaci"><title>Specifying the LDAP Version of Your Client</title>
<para>If you plan to call functions that use LDAP v3 features such as controls
or extended operations, set the protocol version to LDAP v3. By default, clients
built with &DirectorySDKForC; identify themselves to LDAP servers as LDAP
v3 clients, but that was not the case with previous versions.</para>
<para>To specify the LDAP version supported by your client, call the <function>ldap_set_option
</function> function and set the <literal>LDAP_OPT_PROTOCOL_VERSION</literal> option
to the value <literal>3</literal>.</para>
<example><title>Passing the LDAP Protocol Version Number</title>
<programlisting>...
version = LDAP_VERSION3;
ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &amp;version );
...</programlisting>
</example>
<para>After setting this option, as part of the authentication process, your
client sends the supported LDAP version number to the server. By setting the
version, you allow the server to determine whether or not to enable LDAP v3
features.</para>
<para>LDAP v3 allows you to perform LDAP operations without first binding
to the server. An LDAP v3 server assumes that the client is LDAP v3 compliant
if the client issues non-bind operations before the client issues a bind.</para>
</sect3>
<sect3 id="setting-connection-timeout"><title>Setting Connection Timeout</title>
<para>Clients that use &DirectorySDKForC; can control the TCP/IP level
timeout. When the TCP/IP timeout option is not set, an attempt to connect
to a server blocks until the connection completes or the system times out.
By using the <literal>LDAP_X_OPT_CONNECT_TIMEOUT</literal> option, you can
adjust how long to wait for a connection.</para>
<para>You specify the timeout as an <literal>int</literal> number of milliseconds,
then call the <function>ldap_set_option</function> function, passing the <literal>
LDAP_X_OPT_CONNECT_TIMEOUT</literal> option.</para>
<example><title>Passing Connection Timeout Preferences</title>
<para>The following example sets the connection timeout to one second.</para>
<programlisting>int timeout = 1000; /* 1000 milliseconds == 1 second */
ldap_set_option( ld, LDAP_X_OPT_CONNECT_TIMEOUT, &amp;timeout );</programlisting>
</example>
<itemizedlist>
<para>The <literal>LDAP_X_OPT_CONNECT_TIMEOUT</literal> option can be set
using the following values as well:</para>
<listitem><para><literal>LDAP_X_IO_TIMEOUT_NO_WAIT</literal></para><para>Return
immediately if the server cannot be reached.</para></listitem>
<listitem><para><literal>LDAP_X_IO_TIMEOUT_NO_TIMEOUT</literal></para><para>Wait
indefinitely for the server to connect.</para></listitem>
</itemizedlist>
<para>By passing <literal>NULL</literal> as the first parameter to the <function>
ldap_set_option</function> function, you can set the default timeout for all
connections used by your application.</para></sect3>
</sect2>
</sect1>
<sect1 id="bdacj"><title>Binding and Authenticating to an LDAP Server With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>binding and authenticating</secondary>
</indexterm><indexterm>
<primary>binding</primary>
<secondary>with C SDK</secondary>
</indexterm>
<para>When connecting to the LDAP server, your client might need to send a
bind request.</para>
<itemizedlist>
<para>A bind request should be sent if either of the following are true.</para>
<listitem><para>You want to authenticate to the server to add or modify entries
in a directory that requires authentication as a user with certain access
privileges.</para></listitem>
<listitem><para>You are connecting to an LDAP v2 server. LDAP v2 servers typically
require clients to bind before any operations can be performed.</para>
</listitem>
</itemizedlist>
<itemizedlist>
<para>The bind request should contain the following information:</para>
<listitem><para> LDAP version of the client</para></listitem>
<listitem><para> Method of authentication to use</para></listitem>
<listitem><para> DN that the client is attempting to authenticate as</para>
</listitem>
<listitem><para> Credentials to be used for authentication</para></listitem>
</itemizedlist>
<para>LDAP clients can also bind anonymously to the LDAP server if, for example,
the server is configured not to require authentication for a simple directory
search.</para>
<sect2 id="bdaco"><?Pub Caret1><title>Using Simple Authentication With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>methods of authentication</secondary>
<tertiary>simple authentication</tertiary>
</indexterm><indexterm>
<primary>authentication</primary>
<secondary>C SDK</secondary>
<tertiary>simple</tertiary>
</indexterm>
<itemizedlist>
<para>If you plan to use simple authentication, call one of the following
functions:</para>
<listitem><para><function>ldap_simple_bind_s</function> is a synchronous function
for use if you want to wait for the bind operation to complete before the
function returns.</para><para>See <olink targetptr="bdacp">Performing a Synchronous
Authentication Operation</olink></para></listitem>
<listitem><para><function>ldap_simple_bind</function> is an asynchronous function
for use if you do not want to wait for the bind operation to complete. With
this function, you can perform other work while periodically checking for
the results of the bind operation.</para><para>See <olink targetptr="bdacq">Performing
an Asynchronous Authentication Operation</olink></para></listitem>
</itemizedlist>
<para>For more information about the differences between the types of functions,
see <olink targetptr="bdacv">Synchronous and Asynchronous Functions</olink>.</para>
<sect3 id="bdacp"><title>Performing a Synchronous Authentication Operation</title>
<para>If you want to wait for the bind operation to complete before continuing,
call <function>ldap_simple_bind_s</function>. This function returns <errorcode>LDAP_SUCCESS
</errorcode> if the operation completed successfully, or an LDAP result code
if a problem occurred. See <function>ldap_simple_bind_s</function> in <olink targetptr="bdavj">ldap_simple_bind_s</olink> for a list of result codes returned.
</para>
<para>If you specify a DN but no password, your client binds to the server
anonymously. If you want a <literal>NULL</literal> password to be rejected
as incorrect, you must write code to perform the check before you call <function>
ldap_simple_bind_s</function>.</para>
<para>The following example uses the synchronous <function>ldap_simple_bind_s</function> function
to authenticate user Barbara Jensen to the LDAP server.</para>
<example id="csdk-sync-auth-example"><title>Performing Synchronous Authentication
</title>
<programlisting>#include &lt;stdio.h>
#include "ldap.h"
/* Change these as needed. */
#define HOSTNAME "localhost"
#define PORTNUMBER LDAP_PORT
#define BIND_DN "uid=bjensen,ou=People,dc=example,dc=com"
#define BIND_PW "hifalutin"
LDAP *ld;
int rc;
/* Get a handle to an LDAP connection. Use prldap_init() for IPv6. */
if ( (ld = ldap_init( HOSTNAME, PORTNUMBER )) == NULL ) {
perror( "ldap_init" );
return( 1 );
}
/* Print out an informational message. */
printf( "Binding to server %s:%d\n", HOSTNAME, PORTNUMBER );
printf( "as the DN %s ...\n", BIND_DN );
/* Bind to the LDAP server. */
rc = ldap_simple_bind_s( ld, BIND_DN, BIND_PW );
if ( rc != LDAP_SUCCESS ) {
fprintf(stderr, "ldap_simple_bind_s: %s\n\n", ldap_err2string(rc));
return( 1 );
} else {
printf( "Bind operation successful.\n" );
}
...
/* If you want, you can perform LDAP operations here. */
...
/* Disconnect from the server when done. */
ldap_unbind( ld );
return( 0 );
...</programlisting>
</example>
</sect3>
<sect3 id="bdacq"><title>Performing an Asynchronous Authentication Operation</title>
<para>If you want to perform other work in parallel while waiting for the
bind operation to complete, call <function>ldap_simple_bind</function>. This
function sends an LDAP bind request to the server and returns a message ID
identifying the bind operation. To see if your client has received the results
of the bind operation, call the <function>ldap_result</function> function
with the message ID. If your client has received the results, <function>ldap_result
</function> passes back the information in an <structname>LDAPMessage</structname> structure.
To retrieve error information from <structname>LDAPMessage</structname>, you
can pass the message ID to the <function>ldap_parse_result</function> function. <function>
ldap_parse_result</function> gets the LDAP result code of the operation and
any error messages sent back from the server. This function also retrieves
any controls sent back.</para>
<para>If you specify a DN but no password, your client binds to the server
anonymously. If you want a <literal>NULL</literal> password to be rejected
as incorrect, you need to write code to perform the check before you call <function>
ldap_simple_bind</function>.</para>
<para>The following example uses the asynchronous <function>ldap_simple_bind</function> function
to authenticate user Barbara Jensen to the LDAP server.</para>
<example id="csdk-async-auth-example"><title>Performing Asynchronous Authentication
</title>
<indexterm>
<primary>example programs</primary>
<secondary>asynchronous authentication</secondary>
</indexterm>
<programlisting>#include &lt;stdio.h>
#include "ldap.h"
void do_other_work();
int global_counter = 0;
...
#define HOSTNAME "localhost"
#define PORTNUMBER LDAP_PORT
#define BIND_DN "uid=bjensen,ou=People,dc=example,dc=com"
#define BIND_PW "hifalutin"
...
LDAP *ld;
LDAPMessage *res;
int msgid = 0, rc = 0, parse_rc = 0, finished = 0;
char *matched_msg = NULL, *error_msg = NULL;
char **referrals;
LDAPControl **serverctrls;
struct timeval zerotime;
/* Specify the timeout period for ldap_result(),
which specifies how long the function should block when waiting
for results from the server. */
zerotime.tv_sec = zerotime.tv_usec = 0L;
/* Get a handle to an LDAP connection. Use prldap_init() for IPv6. */
if ( (ld = ldap_init( HOSTNAME, PORTNUMBER )) == NULL ) {
perror( "ldap_init" );
return( 1 );
}
/* Print out an informational message. */
printf( "Binding to server %s:%d\n", HOSTNAME, PORTNUMBER );
printf( "as the DN %s ...\n", BIND_DN );
/* Send an LDAP bind request to the server. */
msgid = ldap_simple_bind( ld, BIND_DN, BIND_PW );
/* If the returned message ID is less than zero, an error occurred. */
if ( msgid &lt; 0 ) {
rc = ldap_get_lderrno( ld, NULL, NULL );
fprintf(stderr, "ldap_simple_bind : %s\n", ldap_err2string(rc));
ldap_unbind( ld );
return( 1 );
}
/* Check to see if the bind operation completed. */
while ( !finished ) {
rc = ldap_result( ld, msgid, 0, &amp;zerotime, &amp;res );
switch ( rc ) {
/* If ldap_result() returns -1, error occurred. */
case -1:
rc = ldap_get_lderrno( ld, NULL, NULL );
fprintf( stderr, "ldap_result: %s\n", ldap_err2string( rc ) );
ldap_unbind( ld );
return ( 1 );
/* If ldap_result() returns 0, the timeout (specified by the
timeout argument) has been exceeded before the client received
the results from the server. Continue calling ldap_result()
to poll for results from the server. */
case 0:
break;
default:
/* The client has received the result of the bind operation. */
finished = 1;
/* Parse this result to determine if the operation was successful.
Note that a non-zero value is passed as the last parameter,
which indicates that the LDAPMessage structure res should be
freed when done. (No need to call ldap_msgfree().) */
parse_rc = ldap_parse_result( ld, res, &amp;rc, &amp;matched_msg,
&amp;error_msg, &amp;referrals, &amp;serverctrls, 1 );
if ( parse_rc != LDAP_SUCCESS ) {
fprintf( stderr, "ldap_parse_result: %s\n",
ldap_err2string( parse_rc ) );
ldap_unbind( ld );
return( 1 );
}
/* Check the results of the operation. */
if ( rc != LDAP_SUCCESS ) {
fprintf( stderr, "ldap_simple_bind: %s\n",
ldap_err2string( rc ) );
/* If the server sent an additional error message,
print it out. */
if ( error_msg != NULL &amp;&amp; *error_msg != '\0' ) {
fprintf( stderr, "%s\n", error_msg );
}
/* If an entry specified by a DN could not be found,
the server may also return the portion of the DN
that identifies an existing entry. */
if ( matched_msg != NULL &amp;&amp; *matched_msg != '\0' ) {
fprintf( stderr,
"Part of the DN that matches an existing entry: %s\n",
matched_msg );
}
ldap_unbind( ld );
return( 1 );
} else {
printf( "Bind operation successful.\n" );
printf( "Counted to %d while waiting for bind op.\n",
global_counter );
}
break;
}
/* Do other work here while waiting for results from the server. */
if ( !finished ) {
do_other_work();
}
}
...
/* If you want, you can perform LDAP operations here. */
...
/* Disconnect from the server when done. */
ldap_unbind( ld );
return( 0 );
...
/* Function that does work while waiting for results from the server. */
void do_other_work() {
global_counter++;
}
...</programlisting>
</example>
</sect3>
</sect2>
<sect2 id="bdacr"><title>Binding Anonymously With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>methods of authentication</secondary>
<tertiary>anonymous authentication</tertiary>
</indexterm><indexterm>
<primary>authentication</primary>
<secondary>C SDK</secondary>
<tertiary>anonymous</tertiary>
</indexterm>
<para>In some cases, you do not need to authenticate to the LDAP server. For
example, if users are performing a search that has no special access permissions,
you need not authenticate before performing the search. To bind as an anonymous
user, call <function>ldap_simple_bind</function> or <function>ldap_simple_bind_s</function>,
and pass <literal>NULL</literal> values for the <parameter>who</parameter> and <parameter>
passwd</parameter> parameters.</para>
<programlisting>rc = ldap_simple_bind_s( ld, NULL, NULL );
</programlisting>
<para>With LDAP v2, the client is required to send a bind request, even when
binding anonymously. That is, bind without specifying a name or password.
With LDAP v3, the client is no longer required to bind to the server if the
client does not need to authenticate.</para></sect2>
</sect1>
<sect1 id="bdacs"><title>Performing LDAP Operations With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>LDAP operations</secondary>
</indexterm><indexterm>
<primary>LDAP operations</primary>
<secondary>with C SDK</secondary>
</indexterm>
<para>After initializing a session with a server and completing the authentication
process, you can perform LDAP operations. The LDAP operations include searching
the directory, adding new entries, updating existing entries, and removing
entries. The following lists LDAP operations and the functions that you can
call to perform the operations.</para>
<table frame="topbot" id="csdk-fcns-ldap-ops"><title>Functions for Performing
LDAP Operations</title>
<tgroup cols="2"><colspec colnum="1" colwidth="50*"><colspec colnum="2"
colwidth="50*">
<thead>
<row>
<entry>
<para>To Perform This Operation</para></entry>
<entry>
<para>Call This API Function</para></entry>
</row>
</thead>
<tbody>
<row>
<entry>
<para>Search for entries</para></entry>
<entry>
<para><function>ldap_search_ext</function></para>
<para><function>ldap_search_ext_s</function></para></entry>
</row>
<row>
<entry>
<para>Determine an attribute&rsquo;s value</para></entry>
<entry>
<para><function>ldap_compare_ext</function></para>
<para><function>ldap_compare_ext_s</function></para></entry>
</row>
<row>
<entry>
<para>Add entries</para></entry>
<entry>
<para><function>ldap_add_ext</function></para>
<para><function>ldap_add_ext_s</function></para></entry>
</row>
<row>
<entry>
<para>Modify entries</para></entry>
<entry>
<para><function>ldap_modify_ext</function></para>
<para><function>ldap_modify_ext_s</function></para></entry>
</row>
<row>
<entry>
<para>Delete entries</para></entry>
<entry>
<para><function>ldap_delete_ext</function></para>
<para><function>ldap_delete_ext_s</function></para></entry>
</row>
<row>
<entry>
<para>Change DN of entries</para></entry>
<entry>
<para><function>ldap_rename_ext</function></para>
<para><function>ldap_rename_ext_s</function></para></entry>
</row>
</tbody>
</tgroup>
</table>
<para>Most LDAP operations can be performed synchronously or asynchronously.
The functions with names that end in <literal>_s</literal> are synchronous.
The remaining ones are asynchronous. For more information about the distinction
between the functions, see <olink targetptr="bdaau">Synchronous and Asynchronous
Operations</olink>.</para></sect1>
<sect1 id="bdact"><title>Closing the Connection to an LDAP Server With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>closing an LDAP server connection</secondary>
</indexterm>
<para>When you have finished performing all necessary LDAP operations, you
need to close the connection to the LDAP server. After you close the connection,
you can no longer use the <structname>LDAP</structname> structure because
the structure is freed from memory.</para>
<itemizedlist>
<para>To close a connection to an LDAP server, call one of the following functions:
</para>
<listitem><para><function>ldap_unbind</function></para></listitem>
<listitem><para><function>ldap_unbind_s</function></para></listitem>
<listitem><para><function>ldap_unbind_ext</function></para></listitem>
</itemizedlist>
<para>Both <function>ldap_unbind</function> and <function>ldap_unbind_s</function> are
identical synchronous functions. These functions use different names so that
each function has a corresponding authentication function, <function>ldap_simple_bind
</function> and <function>ldap_simple_bind_s</function>, to close the server
connection. </para>
<para>The <function>ldap_unbind_ext</function> function allows you to include
explicitly both server and client controls in your unbind request. However,
as the server does not respond to an unbind request, you cannot receive a
response from a server control attached to your unbind request. </para>
<para>The following example closes the current connection with the LDAP server.</para>
<example id="csdk-close-conn-example"><title>Closing an LDAP Server Connection</title>
<programlisting>#include &lt;stdio.h>
#include "ldap.h"
...
LDAP *ld;
int rc;
...
/* After completing your LDAP operations with the server, close
the connection. */
rc = ldap_unbind( ld );
if ( rc != LDAP_SUCCESS ) {
fprintf( stderr, "ldap_unbind: %s\n", ldap_err2string( rc ) );
}
...</programlisting>
</example>
</sect1>
</chapter>

View File

@@ -0,0 +1,438 @@
<!--
Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
Portions copyright 1999 Netscape Communications Corporation. All
Rights Reserved.
The contents of this document are subject to the terms of the
Creative Commons Attribution-ShareAlike 2.5 license or any later
version (the "License"). You may not use this document except in
compliance with the License.
See the License for the specific language governing
permissions and limitations under the License. You can obtain
a copy of the License at
http://creativecommons.org/licenses/by-sa/2.5/legalcode.
-->
<chapter id="csdk-compare"><title>Comparing Attribute Values
With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>comparing attribute values</secondary>
</indexterm><highlights>
<para>This chapter describes how to compare the value of an attribute in an
entry against a specified value.</para>
<itemizedlist>
<para>This chapter covers the following topics:</para>
<listitem><para><olink targetptr="bdahc">Functions for Comparing Attribute
Values With Directory SDK for C</olink></para></listitem>
<listitem><para><olink targetptr="bdahd">Performing Synchronous Comparison
Operations With Directory SDK for C</olink></para></listitem>
<listitem><para><olink targetptr="bdahe">Performing Asynchronous Comparison
Operations With Directory SDK for C</olink></para></listitem>
</itemizedlist>
</highlights>
<sect1 id="bdahc"><title>Functions for Comparing Attribute Values With Directory
SDK for C</title>
<para>&DirectorySDKForC; has functions to determine if an attribute contains
a certain string or binary value.</para>
<itemizedlist>
<para>To determine if an attribute contains a certain <emphasis>string</emphasis> value,
call either of the following functions:</para>
<listitem><para>The synchronous <function>ldap_compare_s</function> function</para>
</listitem>
<listitem><para>The asynchronous <function>ldap_compare</function> function</para>
</listitem>
</itemizedlist>
<itemizedlist>
<para>To determine if an attribute contains a certain <emphasis>binary</emphasis> value,
call either of the following functions:</para>
<listitem><para>The synchronous <function>ldap_compare_ext_s</function> function</para>
</listitem>
<listitem><para>The asynchronous <function>ldap_compare_ext</function> function</para>
</listitem>
</itemizedlist>
</sect1>
<sect1 id="bdahd"><title>Performing Synchronous Comparison Operations With
Directory SDK for C</title>
<indexterm>
<primary>synchronous functions</primary>
<secondary>comparison operation</secondary>
</indexterm>
<para>You can wait for the results of the compare operation to complete before
continuing. Call the synchronous <function>ldap_compare_ext_s</function> function
to compare values in <structname>berval</structname> structures or the synchronous <function>
ldap_compare_s</function> function to compare string values. These functions
send a compare request to the server and block work until the server sends
the results of the operation back to your client.</para>
<itemizedlist>
<para>Both functions return one of the following values after the compare
operation completes:</para>
<listitem><para><errorcode>LDAP_COMPARE_TRUE</errorcode> indicates that the
attribute contains the specified value.</para></listitem>
<listitem><para><errorcode>LDAP_COMPARE_FALSE</errorcode> indicates that the
attribute does not contain the specified value.</para></listitem>
</itemizedlist>
<para>An error code indicates that a problem has occurred during the operation.</para>
<para>The following example calls the synchronous <function>ldap_compare_s</function> function
to determine if an entry has the value <literal>bjensen@example.com</literal> in
the <literal>mail</literal> attribute.</para>
<example id="compare-sync-example"><title>Performing a Synchronous Compare
Operation</title>
<programlisting>#include &lt;stdio.h>
#include "ldap.h"
...
#define COMPARE_DN "uid=bjensen,ou=People,dc=example,dc=com"
#define COMPARE_ATTR "mail"
#define COMPARE_VALUE "bjensen@example.com"
...
LDAP *ld;
char *matched_msg = NULL, *error_msg = NULL;
int rc;
...
/* Perform the compare operation. */
rc = ldap_compare_s( ld, COMPARE_DN, COMPARE_ATTR, COMPARE_VALUE );
switch( rc ) {
case LDAP_COMPARE_TRUE:
printf( "%s has the value %s in the %s attribute.\n", COMPARE_DN,
COMPARE_VALUE, COMPARE_ATTR );
break;
case LDAP_COMPARE_FALSE:
printf( "%s does not have the value %s in the %s attribute.\n",
COMPARE_DN, COMPARE_VALUE, COMPARE_ATTR );
break;
default:
fprintf( stderr, "ldap_compare_s: %s\n", ldap_err2string( rc ) );
ldap_get_lderrno( ld, &amp;matched_msg, &amp;error_msg );
if ( error_msg != NULL &amp;&amp; *error_msg != '\0' ) {
fprintf( stderr, "%s\n", error_msg );
}
if ( matched_msg != NULL &amp;&amp; *matched_msg != '\0' ) {
fprintf( stderr,
"Part of the DN that matches an existing entry: %s\n",
matched_msg );
}
break;
}
ldap_unbind_s( ld );
...</programlisting>
</example>
<para>The following sample program calls the synchronous <function>ldap_compare_s
</function> function. The sample program uses this function to determine if
a user entry has the value <literal>bjensen@example.com</literal> in the <literal>
mail</literal> attribute.</para>
<example id="compare-sync-full-example"><title>Sample Synchronous Compare
Program</title>
<programlisting>#include &lt;stdio.h>
#include "ldap.h"
/* Change these as needed. */
#define HOSTNAME "localhost"
#define PORTNUMBER LDAP_PORT
#define COMPARE_DN "uid=bjensen,ou=People,dc=example,dc=com"
#define COMPARE_ATTR "mail"
#define COMPARE_VALUE "bjensen@example.com"
int
main( int argc, char **argv )
{
LDAP *ld;
char *matched_msg = NULL, *error_msg = NULL;
int rc;
/* Get a handle to an LDAP connection. Use prldap_init() for IPv6. */
if ( (ld = ldap_init( HOSTNAME, PORTNUMBER )) == NULL ) {
perror( "ldap_init" );
return( 1 );
}
/* Bind anonymously to the server. */
rc = ldap_simple_bind_s( ld, NULL, NULL );
if ( rc != LDAP_SUCCESS ) {
fprintf( stderr, "ldap_simple_bind_s: %s\n", ldap_err2string( rc ) );
ldap_get_lderrno( ld, &amp;matched_msg, &amp;error_msg );
if ( error_msg != NULL &amp;&amp; *error_msg != '\0' ) {
fprintf( stderr, "%s\n", error_msg );
}
if ( matched_msg != NULL &amp;&amp; *matched_msg != '\0' ) {
fprintf( stderr,
"Part of the DN that matches an existing entry: %s\n",
matched_msg );
}
ldap_unbind_s( ld );
return( 1 );
}
/* Perform the compare operation. */
rc = ldap_compare_s( ld, COMPARE_DN, COMPARE_ATTR, COMPARE_VALUE );
switch( rc ) {
case LDAP_COMPARE_TRUE:
printf( "%s has the value %s in the %s attribute.\n",
COMPARE_DN, COMPARE_VALUE, COMPARE_ATTR );
break;
case LDAP_COMPARE_FALSE:
printf( "%s does not have the value %s in the %s attribute.\n",
COMPARE_DN, COMPARE_VALUE, COMPARE_ATTR );
break;
default:
fprintf( stderr, "ldap_compare_s: %s\n", ldap_err2string( rc ) );
ldap_get_lderrno( ld, &amp;matched_msg, &amp;error_msg );
if ( error_msg != NULL &amp;&amp; *error_msg != '\0' ) {
fprintf( stderr, "%s\n", error_msg );
}
if ( matched_msg != NULL &amp;&amp; *matched_msg != '\0' ) {
fprintf( stderr,
"Part of the DN that matches an existing entry: %s\n",
matched_msg );
}
break;
}
ldap_unbind_s( ld );
return 0;
}</programlisting>
</example>
</sect1>
<sect1 id="bdahe"><title>Performing Asynchronous Comparison Operations With
Directory SDK for C</title>
<indexterm>
<primary>asynchronous functions</primary>
<secondary>comparison operation</secondary>
</indexterm>
<para>You can perform other work in parallel while waiting for the comparison
to complete. Call the asynchronous <function>ldap_compare_ext</function> function
to compare values in <structname>berval</structname> structures or the asynchronous <function>
ldap_compare</function> function to compare string values. These functions
send a compare request to the server and return an <errorcode>LDAP_SUCCESS</errorcode> result
code if the request was successfully sent, or an LDAP result code if an error
occurred.</para>
<para>Both functions pass back a message ID identifying the compare operation.
To determine whether the server sent a response for this operation to your
client, call the <function>ldap_result</function> function and pass in the
message ID. The <function>ldap_result</function> function uses the message
ID to determine if the server sent the results of the compare operation. The <function>
ldap_result</function> function passes back the results in an <structname>LDAPMessage
</structname> structure. You can call the <function>ldap_parse_result</function> function
to parse the <structname>LDAPMessage</structname> structure to determine if
the operation was successful.</para>
<itemizedlist>
<para>The result code should be one of the following:</para>
<listitem><para><errorcode>LDAP_COMPARE_TRUE</errorcode> indicates that the
attribute contains the specified value.</para></listitem>
<listitem><para><errorcode>LDAP_COMPARE_FALSE</errorcode> indicates that the
attribute does not contain the specified value.</para></listitem>
</itemizedlist>
<para>An error code indicates that a problem occurred during the operation.</para>
<para>The following example calls the asynchronous <function>ldap_compare</function> function
to determine if an entry has the value <literal>bjensen@example.com</literal> in
the <literal>mail</literal> attribute.</para>
<example id="compare-async-example"><title>Performing an Asynchronous Compare
Operation</title>
<programlisting>#include &lt;stdio.h>
#include "ldap.h"
...
#define COMPARE_DN "uid=bjensen,ou=People,dc=example,dc=com"
#define COMPARE_ATTR "mail"
#define COMPARE_VALUE "bjensen@example.com"
...
LDAP *ld;
LDAPMessage *res;
LDAPControl **serverctrls;
char *matched_msg = NULL, *error_msg = NULL;
char **referrals;
int rc, parse_rc, msgid, finished = 0;
struct timeval zerotime;
zerotime.tv_sec = zerotime.tv_usec = 0L;
...
/* Send the LDAP compare request. */
msgid = ldap_compare( ld, COMPARE_DN, COMPARE_ATTR, COMPARE_VALUE );
if ( msgid &lt; 0 ) {
fprintf( stderr, "ldap_compare: %s\n", ldap_err2string( rc ) );
ldap_unbind( ld );
return( 1 );
}
/* Poll the server for the results of the LDAP compare operation. */
while ( !finished ) {
rc = ldap_result( ld, msgid, 0, &amp;zerotime, &amp;res );
switch ( rc ) {
case -1:
/* An error occurred. */
rc = ldap_get_lderrno( ld, NULL, NULL );
fprintf( stderr, "ldap_result: %s\n", ldap_err2string( rc ) );
ldap_unbind( ld );
return( 1 );
case 0:
/* The timeout period specified by zerotime was exceeded, so
call ldap_result() again and continue to poll for the
results. */
break;
default:
/* The client has received the results of the
LDAP compare operation from the server. */
finished = 1;
/* Parse the results received from the server.*/
parse_rc = ldap_parse_result( ld, res, &amp;rc, &amp;matched_msg,
&amp;error_msg, &amp;referrals, &amp;serverctrls, 1 );
if ( parse_rc != LDAP_SUCCESS ) {
fprintf( stderr, "ldap_parse_result: %s\n",
ldap_err2string( parse_rc ) );
ldap_unbind( ld );
return( 1 );
}
/* Check the results of the LDAP compare operation. */
switch ( rc ) {
case LDAP_COMPARE_TRUE:
printf( "%s has the value %s in the %s attribute.\n",
COMPARE_DN, COMPARE_VALUE, COMPARE_ATTR );
break;
case LDAP_COMPARE_FALSE:
printf( "%s does not have the value %s in the %s attribute.\n",
COMPARE_DN, COMPARE_VALUE, COMPARE_ATTR );
break;
default:
fprintf( stderr, "ldap_compare: %s\n", ldap_err2string( rc ) );
if ( error_msg != NULL &amp; *error_msg != '\0' ) {
fprintf( stderr, "%s\n", error_msg );
}
if ( matched_msg != NULL &amp;&amp; *matched_msg != '\0' ) {
fprintf( stderr,
"Part of the DN that matches an existing entry: %s\n",
matched_msg );
}
break;
}
}
}
...</programlisting>
</example>
<para>The following sample program calls the asynchronous <function>ldap_compare</function> function.
The sample program uses this function to determine if a user entry has the
value <literal>bjensen@example.com</literal> in the <literal>mail</literal> attribute.
</para>
<example id="compare-async-full-example"><title>Sample Asynchronous Compare
Program</title>
<programlisting>#include &lt;stdio.h>
#include "ldap.h"
void do_other_work();
int global_counter = 0;
/* Change these as needed. */
#define HOSTNAME "localhost"
#define PORTNUMBER LDAP_PORT
#define COMPARE_DN "uid=bjensen,ou=People,dc=example,dc=com"
#define COMPARE_ATTR "mail"
#define COMPARE_VALUE "bjensen@example.com"
int
main( int argc, char **argv )
{
LDAP *ld;
LDAPMessage *res;
LDAPControl **serverctrls;
char *matched_msg = NULL, *error_msg = NULL;
char **referrals;
int rc, parse_rc, msgid, finished = 0;
struct timeval zerotime;
zerotime.tv_sec = zerotime.tv_usec = 0L;
/* Get a handle to an LDAP connection. Use prldap_init() for IPv6. */
if ( (ld = ldap_init( HOSTNAME, PORTNUMBER )) == NULL ) {
perror( "ldap_init" );
return( 1 );
}
/* Bind anonymously to the server. */
rc = ldap_simple_bind_s( ld, NULL, NULL );
if ( rc != LDAP_SUCCESS ) {
fprintf( stderr, "ldap_simple_bind_s: %s\n", ldap_err2string( rc ) );
ldap_get_lderrno( ld, NULL, &amp;error_msg );
if ( error_msg != NULL &amp;&amp; *error_msg != '\0' ) {
fprintf( stderr, "%s\n", error_msg );
}
ldap_unbind_s( ld );
return( 1 );
}
/* Send the LDAP compare request. */
msgid = ldap_compare( ld, COMPARE_DN, COMPARE_ATTR, COMPARE_VALUE );
if ( msgid &lt; 0 ) {
fprintf( stderr, "ldap_compare: %s\n", ldap_err2string( rc ) );
ldap_unbind( ld );
return( 1 );
}
/* Poll the server for the results of the LDAP compare operation. */
while ( !finished ) {
rc = ldap_result( ld, msgid, 0, &amp;zerotime, &amp;res );
switch ( rc ) {
case -1:
/* An error occurred. */
rc = ldap_get_lderrno( ld, NULL, NULL );
fprintf( stderr, "ldap_result: %s\n", ldap_err2string( rc ) );
ldap_unbind( ld );
return( 1 );
case 0:
/* The timeout period specified by zerotime was exceeded.
This means that your client has not yet received the
results of the LDAP compare operation.
Break out of this switch statement, and continue calling
ldap_result() to poll for the results. */
break;
default:
/* The client has received the results of the
LDAP compare operation from the server. */
finished = 1;
/* Parse the results received from the server. Note the last
argument is a non-zero value, which indicates that the
LDAPMessage structure will be freed when done. (No need
to call ldap_msgfree().) */
parse_rc = ldap_parse_result( ld, res, &amp;rc, &amp;matched_msg,
&amp;error_msg, &amp;referrals, &amp;serverctrls, 1 );
if ( parse_rc != LDAP_SUCCESS ) {
fprintf( stderr,
"ldap_parse_result: %s\n",
ldap_err2string( parse_rc ) );
ldap_unbind( ld );
return( 1 );
}
/* Check the results of the LDAP compare operation. */
switch ( rc ) {
case LDAP_COMPARE_TRUE:
printf( "%s has the value %s in the %s attribute.\n"
"Counted to %d while waiting for the compare operation.\n",
COMPARE_DN, COMPARE_VALUE, COMPARE_ATTR, global_counter );
break;
case LDAP_COMPARE_FALSE:
printf( "%s does not have the value %s in the %s attribute.\n"
"Counted to %d while waiting for the compare operation.\n",
COMPARE_DN, COMPARE_VALUE, COMPARE_ATTR, global_counter );
break;
default:
fprintf( stderr, "ldap_compare: %s\n", ldap_err2string( rc ) );
if ( error_msg != NULL &amp; *error_msg != '\0' ) {
fprintf( stderr, "%s\n", error_msg );
}
if ( matched_msg != NULL &amp;&amp; *matched_msg != '\0' ) {
fprintf( stderr,
"Part of the DN that matches an existing entry: %s\n",
matched_msg );
}
break;
}
}
/* Do other work while waiting for the results of the
compare operation. */
if ( !finished ) {
do_other_work();
}
}
ldap_unbind( ld );
return 0;
}
/*
* Perform other work while polling for results. This
* doesn't do anything useful, but it could.
*/
void
do_other_work()
{
global_counter++;
}</programlisting>
</example>
</sect1>
</chapter>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,389 @@
<!--
Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
Portions copyright 1999 Netscape Communications Corporation. All
Rights Reserved.
The contents of this document are subject to the terms of the
Creative Commons Attribution-ShareAlike 2.5 license or any later
version (the "License"). You may not use this document except in
compliance with the License.
See the License for the specific language governing
permissions and limitations under the License. You can obtain
a copy of the License at
http://creativecommons.org/licenses/by-sa/2.5/legalcode.
-->
<chapter id="csdk-extop"><title>Extended Operations With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>extended operations</secondary>
</indexterm><highlights>
<para>This chapter explains LDAP v3 extended operations. It also explains
how to use the extended operations supported by your LDAP server.</para>
<itemizedlist>
<para>This chapter covers the following topics:</para>
<listitem><para><olink targetptr="bdajl">How Extended Operations Work With
Directory SDK for C</olink></para></listitem>
<listitem><para><olink targetptr="bdajm">Determining the Extended Operations
Supported With Directory SDK for C</olink></para></listitem>
<listitem><para><olink targetptr="bdajn">Performing an Extended Operation
With Directory SDK for C</olink></para></listitem>
<listitem><para><olink targetptr="extendop-pwdmod">Performing an LDAP Password
Modify Extended Operation With Directory SDK for C</olink></para></listitem>
<listitem><para><olink targetptr="extendedop-starttls">Using Start TLS With
Directory SDK for C</olink></para></listitem>
<listitem><para><olink targetptr="extendop-whoami">Performing a Who Am I?
Extended Operation With Directory SDK for C</olink></para></listitem>
</itemizedlist>
</highlights>
<sect1 id="bdajl"><title>How Extended Operations Work With Directory SDK for
C</title>
<para>Extended operations are part of LDAP v3. Each extended operation is
identified by an object identifier (OID). LDAP clients can request the operation
by sending an extended operation request.</para>
<itemizedlist>
<para>Within the request, the client specifies the following:</para>
<listitem><para>The OID of the extended operation that should be performed</para>
</listitem>
<listitem><para>Data specific to the extended operation</para></listitem>
</itemizedlist>
<para>The server receives the request, then performs the extended operation.
The server sends back a response to the client that contains an OID, and any
additional data.</para>
<para>To use extended operations, both the server and the client must understand
the specific extended operation to be performed. From the LDAP server perspective, &cnDirectoryServer; supports
a server plug-in interface that you can use to add support for extended operations.
</para></sect1>
<sect1 id="bdajm"><title>Determining the Extended Operations Supported With &DirectorySDKForC;</title>
<para>To determine the extended operations supported by the server, get the
root DSE of the server, and check the <literal>supportedExtension</literal> attribute.
The values of this attribute are the OIDs of the extended operations supported
by this server. If the root DSE does not have a <literal>supportedExtension</literal> attribute,
the server does not support any extended operations. See <olink targetptr="bdahv">
To Get the Root DSE</olink> for instructions on reading that entry.</para>
</sect1>
<sect1 id="bdajn"><title>Performing an Extended Operation With &DirectorySDKForC;</title>
<itemizedlist>
<para>To perform an extended operation, for which no specialized API exists,
call one of the following functions:</para>
<listitem><para>The synchronous <function>ldap_extended_operation_s</function> function
</para></listitem>
<listitem><para>The asynchronous <function>ldap_extended_operation</function> function
</para></listitem>
</itemizedlist>
<para>Both of these functions allow you to specify the OID of the extended
operation and the data that you want applied to the operation.</para>
<para>Before calling the function to perform an LDAP extended operation, make
sure to specify that your client is using version 3 of LDAP. If you do not,
an <errorcode>LDAP_NOT_SUPPORTED</errorcode> result code is returned. For
details, see <olink targetptr="bdaci">Specifying the LDAP Version of Your
Client</olink>.</para>
<sect2 id="bdajo"><title>Synchronous Extended Operation</title>
<para>If you want to wait for the results of an LDAP extended operation to
complete before continuing, call the synchronous <function>ldap_extended_operation_s
</function> function. This function sends a SASL bind request to the server.
The server blocks other work until the server sends the results of the operation
back to your client.</para>
<para><function>ldap_extended_operation_s</function> returns <errorcode>LDAP_SUCCESS
</errorcode> if the operation completed successfully, or an error code if
a problem occurred. See the documentation for the <olink targetptr="bdarv">ldap_extended_operation_s
</olink> function for a list of the possible result codes.</para></sect2>
<sect2 id="bdajp"><title>Asynchronous Extended Operation</title>
<para>If you want to perform other work in parallel while waiting for an LDAP
extended operation to complete, perform the following procedure.</para>
<task><title>To Perform an Asynchronous Extended Operation</title>
<procedure>
<step><para>Call the asynchronous <function>ldap_extended_operation</function> function
to send an LDAP extended operation request.</para><para>This function returns
an <errorcode>LDAP_SUCCESS</errorcode> result code if the request was successfully
sent, or an LDAP result code if an error occurred while sending the request.
The function also sets the <literal>msgidp</literal> argument to point to
a message ID identifying the extended operation. To determine whether the
server sent a response to your client for this operation, call the <function>ldap_result
</function> function and pass in this message ID. The function passes back
the response in an <structname>LDAPMessage</structname> structure.</para></step>
<step><para>Call the <function>ldap_parse_extended_result</function> function
to parse the <structname>LDAPMessage</structname> structure and retrieve information
from the server&rsquo;s response.</para><para>If the server sent an OID of
an extended operation to your client, the OID is passed back as the <literal>retoidp
</literal> argument. If the server sent data to your client, the data is specified
in the <structname>berval</structname> structure passed back as the <literal>retdatap
</literal> argument.</para></step>
<step><para>Call the <function>ldap_get_lderrno</function> function to get
the LDAP result code for the operation.</para><para>The function returns an <errorcode>
LDAP_SUCCESS</errorcode> result code if the extended operation was performed
successfully, or an LDAP error code if a problem occurred. See the documentation
for the <olink targetptr="bdaru">ldap_extended_operation</olink> function
for a list of result codes that the server can return for this operation.</para>
</step>
</procedure>
<example id="csdk-extop-example">
<title>Perform an Asynchronous Extended Operation</title>
<para>This example client requests an asynchronous extended operation from
the server with OID <literal>1.2.3.4</literal>.</para>
<programlisting>#include &lt;stdio.h>
#include &lt;stdlib.h>
#include &lt;string.h>
#include &lt;time.h>
#include "ldap.h"
/* Name and port of the LDAP server you want to connect to. */
#define MY_HOST "localhost"
#define MY_PORT 389
/* DN of user (and password of user) who you want to authenticate as */
#define MGR_DN "cn=Directory Manager"
#define MGR_PW "23skidoo"
int
main( int argc, char **argv )
{
/* OID of the extended operation that you are requesting */
const char *oidrequest = "1.2.3.4";
char *oidresult;
struct berval valrequest;
struct berval *valresult;
LDAP *ld;
int rc, version;
/* Set up the value that you want to pass to the server */
printf( "Setting up value to pass to server...\n" );
valrequest.bv_val = "My Value";
valrequest.bv_len = strlen( "My Value" );
/* Get a handle to an LDAP connection. Use prldap_init() for IPv6. */
printf( "Getting the handle to the LDAP connection...\n" );
if ( (ld = ldap_init( MY_HOST, MY_PORT )) == NULL ) {
perror( "ldap_init" );
ldap_unbind( ld );
return( 1 );
}
/* Set the LDAP protocol version supported by the client
to 3. (By default, this is set to 2. Extended operations
are part of version 3 of the LDAP protocol.) */
ldap_get_option( ld, LDAP_OPT_PROTOCOL_VERSION, &amp;version );
printf( "Resetting version %d to 3.0...\n", version );
version = LDAP_VERSION3;
ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &amp;version );
/* Authenticate to the directory as the Directory Manager */
printf( "Binding to the directory...\n" );
if ( ldap_simple_bind_s( ld, MGR_DN, MGR_PW ) != LDAP_SUCCESS ) {
ldap_perror( ld, "ldap_simple_bind_s" );
ldap_unbind( ld );
return( 1 );
}
/* Initiate the extended operation */
printf( "Initiating the extended operation...\n" );
if ( ( rc = ldap_extended_operation_s( ld, oidrequest, &amp;valrequest,
NULL, NULL, &amp;oidresult, &amp;valresult ) ) !=
LDAP_SUCCESS ) {
ldap_perror( ld, "ldap_extended_operation failed: " );
ldap_unbind( ld );
return( 1 );
}
/* Get the OID and the value from the result returned by the server. */
printf( "Operation successful.\n" );
printf( "\tReturned OID: %s\n", oidresult );
printf( "\tReturned value: %s\n", valresult->bv_val );
/* Disconnect from the server. */
ldap_unbind( ld );
return 0;
}</programlisting>
</example>
</task>
</sect2>
</sect1>
<sect1 id="extendop-pwdmod"><title>Performing an LDAP Password Modify Extended
Operation With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>extended operations</secondary>
<tertiary>password modify</tertiary>
</indexterm>
<para><ulink url="http://www.ietf.org/rfc/rfc3062.txt" type="text_url">RFC
3062</ulink>, <citetitle>LDAP Password Modify Extended Operation</citetitle>,
describes the extended operation, which is particularly useful for changing
expired passwords.</para>
<task><title>To Perform an LDAP Password Modify Extended Operation</title>
<procedure>
<step><para>Get a connection to the directory that uses LDAP version 3.</para>
</step>
<step><para>Authenticate to the directory.</para>
<stepalternatives>
<step><para>As an administrator, to be able to reset an expired user password
if you do not have the old password</para></step>
<step><para>Anonymously to reset an expired password if you have the old password
</para></step>
<step><para>As the user herself to change the password that has not yet expired</para>
</step></stepalternatives>
</step>
<step><para>Modify the password with the synchronous function <function>ldap_passwd_s
</function> or the asynchronous function <function>ldap_passwd</function> and
use <function>ldap_parse_passwd</function> or <function>ldap_parse_passwd_result</function> to
examine the results.</para></step>
</procedure>
<example>
<title>Performing an LDAP Password Modify Extended Operation</title>
<para>This example changes a password using <function>ldap_passwd_s</function>.</para>
<programlisting>/*
* Use the password modify extended operation to change a password.
*/
#include "examples.h"
int
main( int argc, char **argv )
{
int version;
LDAP *ld;
char *target;
int rc;
struct berval userid;
struct berval oldpasswd;
struct berval newpasswd;
struct berval genpasswd;
/* Use LDAPv3. */
version = LDAP_VERSION3;
if ( ldap_set_option( NULL, LDAP_OPT_PROTOCOL_VERSION, &amp;version )
!= 0 ) {
fprintf( stderr,
"ldap_set_option protocol version to %d failed\n",
version );
return ( 1 );
}
/* Get a handle to an LDAP connection. Use prldap_init() for IPv6. */
if ( (ld = ldap_init( MY_HOST, MY_PORT )) == NULL ) {
perror( "ldap_init" );
return( 1 );
}
/* Authenticate to the directory. */
if ( ldap_simple_bind_s( ld, ENTRYDN, ENTRYPW ) != LDAP_SUCCESS ) {
ldap_perror( ld, "ldap_simple_bind_s" );
return( 1 );
}
/* Change the password using the extended operation. */
userid.bv_val = ENTRYDN;
userid.bv_len = strlen(userid.bv_val);
oldpasswd.bv_val = ENTRYPW;
oldpasswd.bv_len = strlen(oldpasswd.bv_val);
newpasswd.bv_val = "ChangeMe!";
newpasswd.bv_len = strlen(newpasswd.bv_val);
rc = ldap_passwd_s(
ld, &amp;userid, &amp;oldpasswd, &amp;newpasswd, &amp;genpasswd, NULL, NULL );
if ( rc != LDAP_SUCCESS ) {
fprintf( stderr, "ldap_passwd_s: %s\n", ldap_err2string( rc ) );
ldap_unbind( ld );
return( 1 );
} else {
printf( "Successfully changed password for %s\n", userid.bv_val );
}
ldap_unbind( ld );
return( 0 );</programlisting>
<para>When you compile and run this sample program against &cnDirectoryServer; with
a suffix that contains data from <filename>Example.ldif</filename>, the server
produces output similar to this:</para>
<screen>Successfully changed password for uid=bjensen, ou=People, dc=example,dc=com
</screen>
</example>
</task>
</sect1>
<sect1 id="extendedop-starttls"><title>Using Start TLS With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>extended operations</secondary>
<tertiary>start TLS</tertiary>
</indexterm>
<para><ulink url="http://www.ietf.org/rfc/rfc4513.txt" type="text_url">RFC
4513</ulink>, <citetitle>Lightweight Directory Access Protocol (LDAP): Authentication
Methods and Security Mechanisms</citetitle>, describes the extended operation.
Start TLS allows you to connect on a non secure port, and then request transport
layer security.</para>
<para>See <olink targetptr="ssl-start-tls">Starting Transport Layer Security
With Directory SDK for C</olink> for an example of how to use Start TLS.</para>
</sect1>
<sect1 id="extendop-whoami"><title>Performing a Who Am I? Extended Operation
With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>extended operations</secondary>
<tertiary>Who Am I?</tertiary>
</indexterm>
<para>The &ldquo;Who am I?&rdquo; extended operation allows you to retrieve
the authorization identity that is associated with a connection.</para>
<para>This method can involve less code than the standard authorization identity
controls that are described in <olink targetptr="controls-authzid">Using the
Authorization Identity Bind Request Control With Directory SDK for C</olink>.</para>
<task><title>To Perform a Who Am I? Extended Operation</title>
<procedure>
<step><para>Get a connection to the directory that uses LDAP version 3.</para>
</step>
<step><para>Use <function>ldap_whoami</function> and <function>ldap_parse_whoami_result
</function>, or use <function>ldap_whoami_s</function>, to retrieve the authorization
identity.</para></step>
</procedure>
<example>
<title>Getting Authorization Identity</title>
<para>This example retrieves authorization identity by using <function>ldap_whoami_s
</function>.</para>
<programlisting>/*
* Use the Who Am I? extended operation.
*/
#include "examples.h"
int
main( int argc, char **argv )
{
int version;
LDAP *ld;
int rc;
char *authzid;
/* Use LDAPv3. */
version = LDAP_VERSION3;
if ( ldap_set_option( NULL, LDAP_OPT_PROTOCOL_VERSION, &amp;version )
!= 0 ) {
fprintf( stderr,
"ldap_set_option protocol version to %d failed\n",
version );
return ( 1 );
}
/* Get a handle to an LDAP connection. Use prldap_init() for IPv6. */
if ( (ld = ldap_init( MY_HOST, MY_PORT )) == NULL ) {
perror( "ldap_init" );
return( 1 );
}
/* Authenticate to the directory. */
if ( ldap_simple_bind_s( ld, ENTRYDN, ENTRYPW ) != LDAP_SUCCESS ) {
ldap_perror( ld, "ldap_simple_bind_s" );
return( 1 );
}
/* Examine my authorization ID. */
rc = ldap_whoami_s( ld, NULL, NULL, &amp;authzid );
if ( rc != LDAP_SUCCESS ) {
fprintf( stderr, "ldap_whoami_s: %s\n", ldap_err2string( rc ) );
ldap_unbind( ld );
return( 1 );
}
printf( "Authorization ID: %s\n", authzid );
ldap_unbind( ld );
return( 0 );
}</programlisting>
<para>When you compile and run this sample program against &cnDirectoryServer;<?Pub
Caret> with a suffix that contains data from <filename>Example.ldif</filename>,
the server produces output similar to this:</para>
<screen>Authorization ID: dn:uid=bjensen,ou=people,dc=example,dc=com</screen>
</example>
</task>
</sect1>
</chapter>

View File

@@ -0,0 +1,375 @@
<!--
Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
Portions copyright 1999 Netscape Communications Corporation. All
Rights Reserved.
The contents of this document are subject to the terms of the
Creative Commons Attribution-ShareAlike 2.5 license or any later
version (the "License"). You may not use this document except in
compliance with the License.
See the License for the specific language governing
permissions and limitations under the License. You can obtain
a copy of the License at
http://creativecommons.org/licenses/by-sa/2.5/legalcode.
-->
<chapter id="csdk-filter"><title>Using Filter Configuration Files With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>filter configuration files</secondary>
</indexterm><highlights>
<para>This chapter explains how to use LDAP C API functions to work with filter
configuration files.</para>
<itemizedlist>
<para>This chapter covers the following topics:</para>
<listitem><para><olink targetptr="bdafi">Understanding Filter Configuration Files for Directory SDK for C</olink></para></listitem>
<listitem><para><olink targetptr="bdafq">Loading Filter Configuration Files With Directory SDK for C</olink></para>
</listitem>
<listitem><para><olink targetptr="bdafs">Filter Prefixes and Suffixes for Directory SDK for C</olink></para>
</listitem>
<listitem><para><olink targetptr="bdaft">Freeing Filters From Memory With Directory SDK for C</olink></para>
</listitem>
<listitem><para><olink targetptr="bdafu">Creating Filters Programmatically With Directory SDK for C</olink></para>
</listitem>
</itemizedlist>
</highlights>
<sect1 id="bdafi"><title>Understanding Filter Configuration Files for Directory
SDK for C</title>
<para>Filter configuration files can help simplify the process of selecting
the appropriate filter for a search request. A <firstterm>filter configuration
file</firstterm> contains a list of filters that you can load and use in your
searches. You might be writing a client that allows users to search the directory.
Use different search filters tailored for specific types of search criteria.</para>
<para>For example, if the user wants to search for the email address <literal>bjensen@example.com
</literal>, you might want to use this search filter:</para>
<programlisting>(mail=bjensen@example.com)</programlisting>
<para>Similarly, suppose the search term entered by the user contains numbers,
as in <literal>555-1212</literal>. In this case, you might want to use this
search filter:</para>
<programlisting>(telephoneNumber=555-1212)</programlisting>
<para>Rather than write code to find and select the appropriate filter, you
can include the filters in a filter configuration file. For example, the following
section of a filter configuration file specifies one filter for telephone
numbers and two filters for email addresses. The telephone number filter is
used if the search criteria contain one or more numbers. The email filters
are used if the search criteria contain an at sign, <literal>@</literal>.</para>
<example id="filter-conf-example"><title>Section of Filter Configuration File</title>
<programlisting>"people"
"^[0-9][0-9-]*$" " "
"(telephoneNumber=*%v))" "phone number ends with"
"@" " " "(mail=%v)" "email address is"
"(mail=%v*)" "email address starts with"</programlisting>
</example>
<para>You should specify the filters in the order that you want the filters
to be used. For example, if you want to apply the <literal>(mail=%v)</literal> filter
before the <literal>(mail=%v*)</literal> filter, make sure that the filters
appear in that order.</para>
<sect2 id="bdafj"><title>Syntax for Filter Configuration Files</title>
<indexterm>
<primary>filter configuration files</primary>
<secondary>syntax</secondary>
</indexterm>
<para>A filter configuration file has the following format. The variables
are discussed in the following sections.</para>
<example id="filter-config-syntax"><title>Syntax for a Filter Configuration
File</title>
<programlisting><replaceable>tag</replaceable>
<replaceable>pattern1</replaceable> <replaceable>delimiters</replaceable> <replaceable>
filter1-1</replaceable> <replaceable>desc1-1</replaceable> [<replaceable>scope</replaceable>]
<replaceable>filter1-2</replaceable> <replaceable>desc1-2</replaceable> [<replaceable>
scope</replaceable>]
<replaceable>pattern2</replaceable> <replaceable>delimiters</replaceable> <replaceable>
filter2-1</replaceable> <replaceable>desc2-1</replaceable> [<replaceable>scope</replaceable>]
&hellip;</programlisting>
</example>
<sect3 id="bdafk"><title>Tag for Filter Groups</title>
<para>A <replaceable>tag</replaceable> identifies a group of filters. You
can use different tags to distinguish filters for different types of objects.
For example, you can use one tag to represent filters for person entries,
another tag to represent filters for organization entries, and so on.</para>
<programlisting>"people"
&hellip; (<replaceable>filters for searching "person" entries</replaceable>) &hellip;
"organization"
&hellip; (<replaceable>filters for "organization" entries</replaceable>) &hellip;
</programlisting>
<para>When you call functions like <function>ldap_getfirstfilter</function> to
retrieve a filter, you can specify a tag, or part of a tag, as a parameter.
The tag narrows the list of filters that the function can retrieve.</para>
</sect3>
<sect3 id="bdafl"><title>Patterns to Select Filters</title>
<para><replaceable>pattern1</replaceable> and <replaceable>pattern2</replaceable> are
regular expressions used to determine which filter is selected, based on the
search criteria. For example, if you specify <literal>"^[0-9]"</literal> as
the pattern for a filter, the filter is selected for all search criteria that
begin with a number.</para>
<programlisting>"people"
"^[0-9]" &hellip;</programlisting>
</sect3>
<sect3 id="bdafm"><title>Delimiters for Fields</title>
<para><replaceable>Delimiters</replaceable> specifies the delimiters used
to distinguish one field from another field within the search criteria. For
example, if the search criteria consist of a city name and a state abbreviation
separated by a comma, specify a comma as the delimiter.</para></sect3>
<sect3 id="bdafn"><title>Filter Lists</title>
<para><replaceable>filter1-1</replaceable>, <replaceable>filter1-2</replaceable>,
and <replaceable>filter2-1</replaceable> are filters. Use <literal>%v</literal> to
represent the search criteria. For example, to search email addresses, use
the filter <literal>(mail=%v)</literal>. During runtime, if the search criteria <literal>
bjensen@example.com</literal> is entered, the filter becomes <literal>(mail=bjensen@example.com)
</literal>.</para>
<para>The search criteria might consist of a number of delimited fields. For
example, the criteria might have a last name, first name format such as <literal>
Jensen, Barbara</literal>. Use <literal>%v1, %v2, &hellip;, %vn</literal> to
represent the different fields within the search criteria as shown here:</para>
<programlisting>"people"
"^[A-Z]*," "," (&amp;(sn=%v1)(givenName=%v2))</programlisting>
<para>In this example, the delimiter is a comma. The word before the delimiter
replaces <literal>%v1</literal> in the filter. The word after the delimiter
replaces <literal>%v2</literal> in the filter. If the user searches for <literal>
Jensen, Barbara</literal> , the resulting filter is as follows:</para>
<programlisting>(&amp;(sn=Jensen)(givenName=Barbara))</programlisting>
<para>You can also specify ranges of fields. For example, to specify the values
in the first three fields, use <literal>%v1-3</literal>. To specify values
from the third field to the last field, use <literal>%v3-</literal>. To specify
the value in the last field, use <literal>%v$</literal>.</para></sect3>
<sect3 id="bdafo"><title>Descriptions of Filters</title>
<para><replaceable>desc1-1</replaceable>, <replaceable>desc1-2</replaceable>,
and <replaceable>desc2-1</replaceable> are phrases that briefly describe the
filters.</para></sect3>
</sect2>
<sect2 id="bdafp"><title>Filter Parameters</title>
<indexterm>
<primary>search filters</primary>
<secondary>parameters</secondary>
</indexterm>
<para>Filter specifications in the configuration file support the following
parameters:</para>
<variablelist>
<varlistentry><term><literal>%v</literal></term>
<listitem><para>Insert the search criterion as is in place of <literal>%v</literal>.
</para>
<para>For example, if the filter specification is <literal>(mail=%v)</literal>,
entering <literal>bjensen</literal> results in the filter <literal>(mail=bjensen)
</literal>.</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>%v$</literal></term>
<listitem><para>Insert the last word of the search criterion as is in place
of <literal>%v</literal>.</para>
<para>For example, if the filter specification is <literal>(sn=%v$)</literal>,
entering <literal>Barbara Jensen</literal> results in the filter <literal>(sn=Jensen)
</literal>.</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>%v</literal><replaceable>N</replaceable></term>
<listitem><para>Insert the <replaceable>N</replaceable>th word of the criteria
in place of <literal>%v</literal>, where <replaceable>N</replaceable> is a
single digit between 1 and 9.</para>
<para>For example, if the filter specification is <literal>(sn=%v2)</literal>,
entering <literal>Barbara Jensen</literal> results in the filter <literal>(sn=Jensen)
</literal>.</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>%v</literal><replaceable>M</replaceable><literal>-</literal><replaceable>
N</replaceable></term>
<listitem><para>Insert the sequence of the <replaceable>M</replaceable>th
through <replaceable>N</replaceable>th words of the criteria in place of <literal>
%v</literal>. Here, <replaceable>M</replaceable> and <replaceable>N</replaceable> are
single digits between 1 and 9.</para>
<para>For example, if the filter specification is <literal>(cn=%v1-2)</literal>,
entering <literal>Barbara Jensen</literal> results in the filter <literal>(cn=Barbara
Jensen)</literal>.</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>%v</literal><replaceable>N</replaceable><literal>-</literal></term>
<listitem><para>Insert the sequence of the <replaceable>N</replaceable>th
through last words of the criteria in place of <literal>%v</literal>. Here, <replaceable>
N</replaceable> is a single digit between 1 and 9.</para>
<para>For example, if the filter specification is <literal>(cn=%v2-)</literal>,
entering <literal>Ms. Barbara Jensen</literal> results in the filter <literal>(cn=Barbara
Jensen)</literal>.</para>
</listitem>
</varlistentry>
</variablelist>
</sect2>
</sect1>
<sect1 id="bdafq"><title>Loading Filter Configuration Files With Directory
SDK for C</title>
<indexterm>
<primary>filter configuration files</primary>
<secondary>loading</secondary>
</indexterm><indexterm>
<primary>loading filter configuration files</primary>
</indexterm>
<para>To load a filter configuration file, call the <function>ldap_init_getfilter
</function> function. You can also read the filter configuration file from
a buffer in memory by calling the <function>ldap_init_getfilter_buf</function> function.
Both functions return a pointer to an <structname>LDAPFiltDesc</structname> structure,
which contains information about the filter. If an error occurs, both functions
return <literal>NULL</literal>.</para>
<sect2 id="bdafr"><title>Retrieving Filters</title>
<indexterm>
<primary>filter configuration file</primary>
<secondary>retrieving</secondary>
</indexterm>
<para>After loading a filter configuration file into memory, you can retrieve
filters based on the search criteria. For example, the search criteria might
be an email address, <literal>(bjensen@example.com)</literal>. Have your client
automatically search for this value in the <literal>mail</literal> attribute
of person entries.</para>
<para>To retrieve the first filter that matches the search criteria, call
the <function>ldap_getfirstfilter</function> function. To get the next filter
that matches the search criteria, call the <function>ldap_getnextfilter</function> function.
Both functions return a pointer to an <structname>LDAPFiltInfo</structname> structure,
which contains information about the filter, as shown here.<?Pub Caret></para>
<example id="filter-retrieve-conf-example"><title>Retrieving Configuration
Filters</title>
<programlisting>#include &lt;stdio.h>
#include "ldap.h"
&hellip;
LDAP *ld;
LDAPMessage *result, *e;
BerElement *ber;
char *a, *dn;
char **vals;
int i;
LDAPFiltDesc *ldfp;
LDAPFiltInfo *ldfi;
char buf[ 80 ]; /* contains the search criteria */
int found;
&hellip;
/* Load the filter configuration file into an LDAPFiltDesc structure. */
if ( ( ldfp = ldap_init_getfilter( "myfilters.conf" ) ) == NULL ) {
perror( "Cannot open filter configuration file" );
}
/* Select a filter to use when searching for the value in buf.
Use filters under the "people" tag in the filter configuration file. */
found = 0;
for ( ldfi = ldap_getfirstfilter( ldfp, "people", buf ); ldfi != NULL;
ldfi = ldap_getnextfilter( ldfp ) ) {
/* Use the selected filter to search the directory. */
if ( ldap_search_s( ld, "dc=example,dc=com", ldfi->lfi_scope,
ldfi->lfi_filter, NULL, 0, &amp;result ) != LDAP_SUCCESS ) {
ldap_perror( ld, "ldap_search_s" );
return( 1 );
} else {
/* Once a filter gets results back, stop iterating through
the different filters. */
if ( ( found = ldap_count_entries( ld, result ) > 0 ) ) {
break;
} else {
ldap_msgfree( result );
}
}
}
if ( found == 0 ) {
printf( "No matching entries found.\n" );
} else {
printf( "Found %d match%s where %s \"%s\"\n\n", found,
found == 1 ? "" : "es", ldfi->lfi_desc, buf );
}
ldap_msgfree( result );
ldap_getfilter_free( ldfp );
&hellip;</programlisting>
</example>
<para>Suppose that the search criteria is <literal>bjensen@example.com</literal> and
that the client application finds a single matching entry. Then the application
prints the following output:</para>
<programlisting>Found 1 match where email address is bjensen@example.com</programlisting>
</sect2>
</sect1>
<sect1 id="bdafs"><title>Filter Prefixes and Suffixes for Directory SDK for
C</title>
<indexterm>
<primary>search filters</primary>
<secondary>prefixes</secondary>
</indexterm><indexterm>
<primary>search filters</primary>
<secondary>suffixes</secondary>
</indexterm>
<para>If you need to apply a filter to all searches, add a filter prefix and
suffix to all filters. Do not add the criteria to all filters. The prefix
is automatically added to any filter retrieved through the <function>ldap_getfirstfilter
</function> and <function>ldap_getnextfilter</function> functions. The required
suffix <literal>)</literal> needed to balance the number of parentheses is
also added. For example, suppose you use this filter in a filter configuration
file:</para>
<programlisting>(cn=Babs Jensen)</programlisting>
<para>You can retrieve this filter by using <function>ldap_getfirstfilter</function> or <function>
ldap_getnextfilter</function>. These functions get a filter that constrains
your client searches to person entries for the defined filter:</para>
<programlisting>(&amp;(objectClass=person)(cn=Babs Jensen))</programlisting>
<para>To add a prefix and suffix automatically to all filters retrieved from
the filter configuration file, call the <function>ldap_set_filter_additions</function> function.
The following example adds the prefix <literal>(&amp;(objectClass=person)</literal> and
the suffix <literal>)</literal> to each filter retrieved.</para>
<example id="filter-add-affixes-example"><title>Adding Prefixes and Suffixes
to Filters</title>
<programlisting>#include "ldap.h"
&hellip;
LDAPFiltDesc *lfdp;
char *filter_file = "myfilters.conf";
char *prefix = "(&amp;(objectClass=person)";
char *suffix = ")";
&hellip;
lfdp = ldap_init_getfilter( filter_file );
ldap_setfilteraffixes( lfdp, prefix, suffix );
&hellip;</programlisting>
</example>
</sect1>
<sect1 id="bdaft"><title>Freeing Filters From Memory With Directory SDK for
C</title>
<indexterm>
<primary>search filters</primary>
<secondary>freeing from memory</secondary>
</indexterm><indexterm>
<primary>memory</primary>
<secondary>freeing search filters from</secondary>
</indexterm>
<para>When you complete your search, free the <structname>LDAPFiltDesc</structname> structure
from memory. To free <structname>LDAPFiltDesc</structname>, call the <function>ldap_getfilter_free
</function> function as shown here. </para>
<example id="filter-free-example"><title>Freeing Filters From Memory</title>
<programlisting>#include "ldap.h"
&hellip;
LDAPFiltDesc *lfdp;
char *filter_file = "myfilters.conf";
&hellip;
/* Read the filter configuration file into an LDAPFiltDesc structure. */
lfdp = ldap_init_getfilter( filter_file );
&hellip;
/* Retrieve filters and perform searches. */
&hellip;
/* Free the configuration file (the LDAPFiltDesc structure). */
ldap_getfilter_free( lfdp );
&hellip;</programlisting>
</example>
</sect1>
<sect1 id="bdafu"><title>Creating Filters Programmatically With Directory
SDK for C</title>
<indexterm>
<primary>search filters</primary>
<secondary>creating programmatically</secondary>
</indexterm>
<para>You can build your own filters by calling the <function>ldap_create_filter</function> function.
The following example builds the filter <literal>(mail=bjensen@example.com)</literal>.
</para>
<example id="filter-create-example"><title>Creating Filters</title>
<programlisting>char buf[LDAP_FILT_MAXSIZ];
char *pattern = "(%a=%v);
char *attr = "mail";
char *value = "bjensen@example.com";
&hellip;
ldap_create_filter( buf, LDAP_FILT_MAXSIZ, pattern, NULL, NULL, attr,
value, NULL );
&hellip;</programlisting>
</example>
</sect1>
</chapter>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,312 @@
<!--
Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
Portions copyright 1999 Netscape Communications Corporation. All
Rights Reserved.
The contents of this document are subject to the terms of the
Creative Commons Attribution-ShareAlike 2.5 license or any later
version (the "License"). You may not use this document except in
compliance with the License.
See the License for the specific language governing
permissions and limitations under the License. You can obtain
a copy of the License at
http://creativecommons.org/licenses/by-sa/2.5/legalcode.
-->
<chapter id="csdk-urls"><title>LDAP URLs With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>LDAP URLs</secondary>
</indexterm><highlights>
<para>This chapter describes how to use LDAP URLs to search and retrieve data
from the directory.</para>
<itemizedlist>
<para>This chapter covers the following topics:</para>
<listitem><para><olink targetptr="bdahp">Checking an LDAP URL With Directory
SDK for C</olink></para></listitem>
<listitem><para><olink targetptr="bdahq">Getting the Components of an LDAP
URL With Directory SDK for C</olink></para></listitem>
<listitem><para><olink targetptr="bdahr">Freeing the Components of an LDAP
URL With Directory SDK for C</olink></para></listitem>
<listitem><para><olink targetptr="bdahs">Processing an LDAP URL With Directory
SDK for C</olink></para></listitem>
</itemizedlist>
</highlights><?Pub Caret1>
<sect1 id="bdahp"><title>Checking an LDAP URL With &DirectorySDKForC;</title>
<para>To determine whether a URL is an LDAP URL, call the <function>ldap_is_ldap_url
</function> function. This function returns a nonzero value if the URL is
an LDAP URL. If the URL is not an LDAP URL, the function returns <literal>0</literal>.
The following example determines if a URL is an LDAP URL.</para>
<example id="ldap-url-is-ldap-url"><title>Determining Whether a URL Is an
LDAP URL</title>
<programlisting>#include &lt;stdio.h>
#include "ldap.h"
...
char *my_url = "ldap://ldap.example.com/dc=example,dc=com";
...
if ( ldap_is_ldap_url( my_url ) != 0 ) {
printf( "%s is an LDAP URL.\n", my_url );
} else {
printf( "%s is not an LDAP URL.\n", my_url );
}
...</programlisting>
</example>
<para><function>ldap_is_ldap_url</function> determines whether a URL is an
LDAP URL. To verify that an LDAP URL complies with the LDAP URL syntax, you
should call the <function>ldap_url_parse</function> function as detailed in <olink targetptr="bdahq">Getting the Components of an LDAP URL With Directory SDK
for C</olink>.</para></sect1>
<sect1 id="bdahq"><title>Getting the Components of an LDAP URL With &DirectorySDKForC;</title>
<para>To retrieve the individual components of an LDAP URL, call <function>ldap_url_parse
</function>. This function returns the LDAP URL components in an <structname>LDAPURLDesc
</structname> structure as shown in this example.</para>
<example id="ldap-url-ldapurldesc"><title><structname>LDAPURLDesc</structname> Structure
</title>
<programlisting>typedef struct ldap_url_desc {
char *lud_host;
int lud_port;
char *lud_dn;
char **lud_attrs;
int lud_scope;
char *lud_filter;
unsigned long lud_options;
} LDAPURLDesc;</programlisting>
</example>
<para>The following table describes the structure's fields.</para>
<table frame="topbot" pgwide="1" id="ldap-url-ldapurldesc-fields"><title><structname>
LDAPURLDesc</structname> Field Descriptions</title>
<tgroup cols="2"><colspec colnum="1" colwidth="11.10*"><colspec colnum="2"
colwidth="88.90*">
<thead>
<row>
<entry>
<para>Field Name</para></entry>
<entry>
<para>Description</para></entry>
</row>
</thead>
<tbody>
<row>
<entry>
<para><structfield>lud_host</structfield></para></entry>
<entry>
<para>The name of the host in the URL.</para></entry>
</row>
<row>
<entry>
<para><structfield>lud_port</structfield></para></entry>
<entry>
<para>The number of the port in the URL.</para></entry>
</row>
<row>
<entry>
<para><structfield>lud_dn</structfield></para></entry>
<entry>
<para>The distinguished name in the URL.</para></entry>
</row>
<row>
<entry>
<para><structfield>lud_attrs</structfield></para></entry>
<entry>
<para>A pointer to a <literal>NULL</literal> terminated array of the attributes
specified in the URL.</para></entry>
</row>
<row>
<entry>
<para><structfield>lud_scope</structfield></para></entry>
<entry>
<itemizedlist>
<para>The scope of the search specified in the URL. This field can have the
following values:</para>
<listitem><para><literal>LDAP_SCOPE_BASE</literal> specifies a search of the
base entry.</para></listitem>
<listitem><para><literal>LDAP_SCOPE_ONELEVEL</literal> specifies a search
of all entries one level under the base entry, not including the base entry.</para>
</listitem>
<listitem><para><literal>LDAP_SCOPE_SUBTREE</literal> specifies a search of
all entries at all levels under the base entry, including the base entry.</para>
</listitem>
</itemizedlist>
</entry>
</row>
<row>
<entry>
<para><structfield>lud_filter</structfield></para></entry>
<entry>
<para>Search filter included in the URL.</para></entry>
</row>
<row>
<entry>
<para><structfield>lud_options</structfield></para></entry>
<entry>
<para>Options. If <literal>LDAP_URL_OPT_SECURE</literal>, indicates that the
protocol is <literal>ldaps://</literal> instead of <literal>ldap://</literal>.</para>
</entry>
</row>
</tbody>
</tgroup>
</table>
<para>The following example parses an LDAP URL.</para>
<example id="ldap-url-parse-example"><title>Parsing an LDAP URL</title>
<programlisting>#include &lt;stdio.h>
#include "ldap.h"
...
char *my_url =
"ldap://ldap.example.com:1389/dc=example,dc=com?
cn,mail,telephoneNumber?sub?(sn=Jensen)";
LDAPURLDesc *ludpp;
int res, i;
...
if ( ( res = ldap_url_parse( my_url, &amp;ludpp ) ) != 0 ) {
switch( res ){
case LDAP_URL_ERR_NOTLDAP:
printf( "URL does not begin with \"ldap://\"\n" );
break;
case LDAP_URL_ERR_NODN:
printf( "URL missing trailing slash after host or port\n" );
break;
case LDAP_URL_ERR_BADSCOPE:
printf( "URL contains an invalid scope\n" );
break;
case LDAP_URL_ERR_MEM:
printf( "Not enough memory\n" );
break;
default:
printf( "Unknown error\n" );
}
return( 1 );
}
printf( "Components of the URL:\n" );
printf( "Host name: %s\n", ludpp->lud_host );
printf( "Port number: %d\n", ludpp->lud_port );
if ( ludpp->lud_dn != NULL ) {
printf( "Base entry: %s\n", ludpp->lud_dn );
} else {
printf( "Base entry: Root DN\n" );
}
if ( ludpp->lud_attrs != NULL ) {
printf( "Attributes returned: \n" );
for ( i=0; ludpp->lud_attrs[i] != NULL; i++ ) {
printf( "\t%s\n", ludpp->lud_attrs[i] );
}
} else {
printf( "No attributes returned.\n" );
}
printf( "Scope of the search: " );
switch( ludpp->lud_scope ) {
case LDAP_SCOPE_BASE:
printf( "base\n" );
break;
case LDAP_SCOPE_ONELEVEL:
printf( "one\n" );
break;
case LDAP_SCOPE_SUBTREE:
printf( "sub\n" );
break;
default:
printf( "Unknown scope\n" );
}
printf( "Filter: %s\n", ludpp->lud_filter );
...</programlisting>
</example>
<para>The code in <olink targetptr="ldap-url-parse-example">Example 13&ndash;3</olink> prints
each component of the URL as shown in the following example.</para>
<example id="ldap-url-parse-example-output"><title>Results of Parsing an LDAP
URL</title>
<screen>Components of the URL:
Host name: ldap.example.com
Port number: 1389
Base entry: dc=example,dc=com
Attributes returned:
cn
mail
telephoneNumber
Scope of the search: sub
Filter: (sn=Jensen)</screen>
</example>
</sect1>
<sect1 id="bdahr"><title>Freeing the Components of an LDAP URL With &DirectorySDKForC;</title>
<para>When you have finished working with the components of an LDAP URL, you
should free the <structname>LDAPURLDesc</structname> structure from memory
by calling the <function>ldap_free_urldesc</function> function. The following
example parses an LDAP URL. The example then frees the <structname>LDAPURLDesc</structname> structure
from memory, after verifying that the LDAP URL is valid.</para>
<example id="ldap-url-free-example"><title>Freeing the <structname>LDAPURLDesc</structname> Structure
From Memory</title>
<programlisting>#include &lt;stdio.h>
#include "ldap.h"
...
char *my_url = "ldap://ldap.example.com:1389/dc=example,dc=com?cn,mail,
telephoneNumber?sub?(sn=Jensen)";
LDAPURLDesc *ludpp;
int res, i;
...
if ( ( res = ldap_url_parse( my_url, &amp;ludpp ) ) != 0 ) {
switch( res ){
case LDAP_URL_ERR_NOTLDAP:
printf( "URL does not begin with \"ldap://\"\n" );
break;
case LDAP_URL_ERR_NODN:
printf( "URL does not contain a distinguished name\n" );
break;
case LDAP_URL_ERR_BADSCOPE:
printf( "URL contains an invalid scope\n" );
break;
case LDAP_URL_ERR_MEM:
printf( "Not enough memory\n" );
break;
default:
printf( "Unknown error\n" );
}
return( 1 );
}
printf( "URL is a valid LDAP URL\n" );
ldap_free_urldesc( ludpp );
...</programlisting>
</example>
</sect1>
<sect1 id="bdahs"><title>Processing an LDAP URL With &DirectorySDKForC;</title>
<para>To process an LDAP URL search request, call one of the following functions:
</para>
<itemizedlist>
<listitem><para><function>ldap_url_search_s</function> is a synchronous function
that completes the search operation before returning. Call this function if
you need to wait for the operation to finish before continuing other work.
The function returns <errorcode>LDAP_SUCCESS</errorcode> if the operation
completed successfully. If an error occurred, the function returns an error
code.</para></listitem>
<listitem><para><function>ldap_url_search_st</function> is a synchronous function
that allows a certain amount of time for the completion of the search operation.
Call this function to wait for the operation to complete, and to set a timeout
period for the operation.</para></listitem>
<listitem><para><function>ldap_url_search</function> is an asynchronous function
that initiates the search operation but does not wait for the operation to
complete. Call this function if you want to perform other work in parallel
while waiting for the operation to complete. The function returns a message
ID identifying the search operation. To determine whether the operation is
completed or still in progress, call the <function>ldap_result</function> function.
</para><para>After the operation is completed, call the <function>ldap_result2error
</function> function to determine if the operation was successful. If the
operation completed successfully, the <function>ldap_result2error</function> function
returns <errorcode>LDAP_SUCCESS</errorcode>. If an error occurred, the function
returns an error code. </para></listitem>
</itemizedlist>
<para>The following example processes a search request from an LDAP URL.</para>
<example id="ldap-url-search-example"><title>Processing an LDAP URL Search
Request</title>
<programlisting>#include &lt;stdio.h>
#include "ldap.h"
...
LDAP *ld;
LDAPMessage *result;
char *my_url = "ldap://ldap.example.com/dc=example,dc=com?cn,mail,
telephoneNumber?sub?(sn=Jensen)";
/* Process the search request in the URL. */
if ( ldap_url_search_s( ld, my_url, 0, &amp;result ) != LDAP_SUCCESS ) {
ldap_perror( ld, "ldap_url_search_s" );
return( 1 );
}</programlisting>
</example>
</sect1>
</chapter>

View File

@@ -0,0 +1,807 @@
<!--
Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
Portions copyright 1999 Netscape Communications Corporation. All
Rights Reserved.
The contents of this document are subject to the terms of the
Creative Commons Attribution-ShareAlike 2.5 license or any later
version (the "License"). You may not use this document except in
compliance with the License.
See the License for the specific language governing
permissions and limitations under the License. You can obtain
a copy of the License at
http://creativecommons.org/licenses/by-sa/2.5/legalcode.
-->
<chapter id="csdk-multithread"><title>Writing Multithreaded Clients With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>multithreaded clients</secondary>
</indexterm><highlights>
<para>This chapter shows how to write multithreaded LDAP client applications.</para>
<itemizedlist>
<para>This chapter covers the following topics:</para>
<listitem><para><olink targetptr="bdajf">Specifying Thread Functions With Directory SDK for C</olink></para>
</listitem>
<listitem><para><olink targetptr="bdajj">POSIX Thread Client Application With Directory SDK for C</olink></para>
</listitem>
</itemizedlist>
<para>The &DirectorySDKForC; APIs are thread-safe. By default, the APIs
use POSIX thread-safe primitives. Therefore, unless you specify your own thread
functions, standard best practices for POSIX threading apply.</para>
</highlights>
<sect1 id="bdajf"><title>Specifying Thread Functions With Directory SDK for
C</title>
<para>You can write a multithreaded client with different threads accessing
the same <structname>LDAP</structname> structure. Use the POSIX thread API.
Alternatively, set up the session defining your own structures such that threads
do not interfere with data of other threads.</para>
<para>The <literal>LDAP_OPT_THREAD_FN_PTRS</literal> session option lets you
set up an <structname>ldap_thread_fns</structname> structure. The structure
identifies the functions that are called in multithreaded environments. For
example, the structure can define functions to lock critical sections of code
and to handle errors. As this structure lets you specify these functions,
you can use &DirectorySDKForC; in different types of threading environments.</para>
<sect2 id="bdajg"><title>Setting Up the <structname>ldap_thread_fns</structname> Structure
</title>
<para>You can write a multithreaded client in which different threads use
the same LDAP connection. Set up the <structname>ldap_thread_fns</structname> structure.
Then identify the functions that you want to use in the <structname>ldap_thread_fns
</structname> structure.</para>
<example id="ldap-thread-fns-prototype"><title><structname>ldap_thread_fns</structname> Structure
</title>
<programlisting>struct ldap_thread_fns {
LDAP_TF_MUTEX_ALLOC_CALLBACK *ltf_mutex_alloc;
LDAP_TF_MUTEX_FREE_CALLBACK *ltf_mutex_free;
LDAP_TF_MUTEX_LOCK_CALLBACK *ltf_mutex_lock;
LDAP_TF_MUTEX_UNLOCK_CALLBACK *ltf_mutex_unlock;
LDAP_TF_GET_ERRNO_CALLBACK *ltf_get_errno;
LDAP_TF_SET_ERRNO_CALLBACK *ltf_set_errno;
LDAP_TF_GET_LDERRNO_CALLBACK *ltf_get_lderrno;
LDAP_TF_SET_LDERRNO_CALLBACK *ltf_set_lderrno;
void *ltf_lderrno_arg;
};</programlisting>
</example>
<para>The fields of the<?Pub Caret> <structname>ldap_thread_fns</structname> structure
are described in the following table.</para>
<table frame="topbot" pgwide="1" id="ldap-thread-fns-fields"><title><structname>ldap_thread_fns
</structname> Field Descriptions</title>
<tgroup cols="2"><colspec colnum="1" colwidth="25*"><colspec colnum="2"
colwidth="75*">
<thead>
<row>
<entry>
<para>Field</para></entry>
<entry>
<para>Description</para></entry>
</row>
</thead>
<tbody>
<row>
<entry>
<para><structfield>*ltf_mutex_alloc</structfield></para></entry>
<entry>
<para>Function pointer for allocating a mutex. This function is called by
the client when needed if the function pointer is not <literal>NULL</literal>.</para>
</entry>
</row>
<row>
<entry>
<para><structfield>*ltf_mutex_free</structfield></para></entry>
<entry>
<para>Function pointer for freeing a mutex. This function is called by the
client when needed if the function pointer is not <literal>NULL</literal>.</para>
</entry>
</row>
<row>
<entry>
<para><structfield>*ltf_mutex_lock</structfield></para></entry>
<entry>
<para>Function pointer for locking critical sections of code. This function
is called by the client when needed if the function pointer is not <literal>NULL</literal>.
</para></entry>
</row>
<row>
<entry>
<para><structfield>*ltf_mutex_unlock</structfield></para></entry>
<entry>
<para>Function pointer for unlocking critical sections of code. This function
is called by the client when needed if the function pointer is not <literal>NULL</literal>.
</para></entry>
</row>
<row>
<entry>
<para><structfield>*ltf_get_errno</structfield></para></entry>
<entry>
<para>Function pointer for getting the value of the <systemitem>errno</systemitem> variable.
This function is called by the client when needed if the function pointer
is not <literal>NULL</literal>. In a threaded environment, <systemitem>errno</systemitem> is
typically redefined. The error structure has a value for each thread, rather
than a global value for the entire process. This redefinition is done at compile
time. The <filename>libldap</filename> library does not know what method your
code and your threading environment use to get the value of <systemitem>errno</systemitem> for
each thread. The library therefore calls this function to return the value
of <systemitem>errno</systemitem>.</para></entry>
</row>
<row>
<entry>
<para><structfield>*ltf_set_errno</structfield></para></entry>
<entry>
<para>Function pointer for setting the value of the <systemitem>errno</systemitem> variable.
This function is called by the client when needed if the function pointer
is not <literal>NULL</literal>. In a threaded environment, <systemitem>errno</systemitem> is
typically redefined. The error structure has a value for each thread, rather
than a global value for the entire process. This redefinition is done at compile
time. The <filename>libldap</filename> library does not know what method your
code and your threading environment use to get the value of <systemitem>errno</systemitem> for
each thread. The library therefore calls this function to set the value of <systemitem>
errno</systemitem>.</para></entry>
</row>
<row>
<entry>
<para><structfield>*ltf_get_lderrno</structfield></para></entry>
<entry>
<para>Function pointer for getting error values from calls to functions in
the <filename>libldap</filename> library. This function is called by the client
when needed if the function pointer is not <literal>NULL</literal>. If this
function pointer is not set, the <filename>libldap</filename> library records
these errors in fields in the <structname>LDAP</structname> structure.</para>
</entry>
</row>
<row>
<entry>
<para><structfield>*ltf_set_lderrno</structfield></para></entry>
<entry>
<para>Function pointer for setting error values from calls to functions in
the <filename>libldap</filename> library. This function is called by the client
when needed if the function pointer is not <literal>NULL</literal>. If this
function pointer is not set, the <filename>libldap</filename> library records
these errors in fields in the <structname>LDAP</structname> structure.</para>
</entry>
</row>
<row>
<entry>
<para><structfield>*ltf_lderrno_arg</structfield></para></entry>
<entry>
<para>Additional parameter passed to the functions for getting and setting
error values from calls to functions in the <filename>libldap</filename> library. <literal>
*ltf_get_lderrno</literal> and <literal>*ltf_set_lderrno</literal> identify
these functions.</para></entry>
</row>
</tbody>
</tgroup>
</table>
</sect2>
<sect2 id="bdajh"><title>Setting Up the <structname>ldap_extra_thread_fns</structname> Structure
</title>
<para>&DirectorySDKForC; provides a structure, <structname>ldap_extra_thread_fns
</structname>, that specifies <emphasis>additional</emphasis> thread functions
for locking. The structure also specifies thread functions for <firstterm>semaphores
</firstterm>, which are protected variables. The <structname>ldap_extra_thread_fns
</structname> structure is defined in the following example.</para>
<example id="ldap-extra-thread-fns-prototype"><title>Declaring the <structname>ldap_extra_thread_fns
</structname> Structure</title>
<programlisting>struct ldap_extra_thread_fns {
LDAP_TF_MUTEX_TRYLOCK_CALLBACK *ltf_mutex_trylock;
LDAP_TF_SEMA_ALLOC_CALLBACK *ltf_sema_alloc;
LDAP_TF_SEMA_FREE_CALLBACK *ltf_sema_free;
LDAP_TF_SEMA_WAIT_CALLBACK *ltf_sema_wait;
LDAP_TF_SEMA_POST_CALLBACK *ltf_sema_post;
LDAP_TF_THREADID_CALLBACK *ltf_threadid_fn;
};</programlisting>
</example>
<para>&DirectorySDKForC; supports only the <literal>LDAP_TF_TREADID_CALLBACK
*ltf_threadid_fn</literal> function. You use this function callback in a multithreaded
application to improve the performance of thread locking. The supported function
must return an identifier that is unique to the calling thread, like <function>pthread_self
</function> does. If any of the other extra thread callback functions are
set, the extra functions are ignored. </para></sect2>
<sect2 id="bdaji"><title>Setting Session Options</title>
<para>After you set up the <structname>ldap_thread_fns</structname> structure,
associate the structure with the current session. Call the <function>ldap_set_option
</function> function and pass <literal>LDAP_OPT_THREAD_FN_PTRS</literal> as
the value of the <literal>option</literal> parameter. Pass a pointer to the <structname>
ldap_thread_fns</structname> structure as the value of the <literal>optdata</literal> parameter.
</para>
<example id="ldap-thread-fns-example"><title>Associating the <structname>ldap_thread_fns
</structname> Structure With the Current Session</title>
<programlisting>#include &lt;stdio.h>
#include &lt;malloc.h>
#include &lt;errno.h>
#include &lt;pthread.h>
#include "ldap.h"
struct ldap_thread_fns tfns;
...
/* Set up the ldap_thread_fns structure with pointers
to the functions that you want called */
memset( &amp;tfns, '\0', sizeof(struct ldap_thread_fns) );
/* Specify the functions that you want called */
/* Call the my_mutex_alloc() function whenever mutexes
need to be allocated */
tfns.ltf_mutex_alloc = (void *(*)(void)) my_mutex_alloc;
/* Call the my_mutex_free() function whenever mutexes
need to be destroyed */
tfns.ltf_mutex_free = (void (*)(void *)) my_mutex_free;
/* Call the pthread_mutex_lock() function whenever a
thread needs to lock a mutex. */
tfns.ltf_mutex_lock = (int (*)(void *)) pthread_mutex_lock;
/* Call the pthread_mutex_unlock() function whenever a
thread needs to unlock a mutex. */
tfns.ltf_mutex_unlock = (int (*)(void *)) pthread_mutex_unlock;
/* Call the get_errno() function to get the value of errno */
tfns.ltf_get_errno = get_errno;
/* Call the set_errno() function to set the value of errno */
tfns.ltf_set_errno = set_errno;
/* Call the get_ld_error() function to get error values from
calls to functions in the libldap library */
tfns.ltf_get_lderrno = get_ld_error;
/* Call the set_ld_error() function to set error values for
calls to functions in the libldap library */
tfns.ltf_set_lderrno = set_ld_error;
/* Don&rsquo;t pass any extra parameter to the functions for
getting and setting libldap function call errors */
tfns.ltf_lderrno_arg = NULL;
...
/* Set the session option that specifies the functions to call for
multi-threaded clients */
if (ldap_set_option( ld, LDAP_OPT_THREAD_FN_PTRS, (void *) &amp;tfns) != 0) {
ldap_perror( ld, "ldap_set_option: thread pointers" );
}
...</programlisting>
</example>
<para>If you <emphasis>also</emphasis> set up the <structname>ldap_extra_thread_fns
</structname> structure, associate the structure with the current session.
Call the <function>ldap_set_option</function> function, passing <literal>LDAP_OPT_EXTRA_THREAD_FN_PTRS
</literal> as the value of the <literal>option</literal> parameter. Also pass
a pointer to the <structname>ldap_extra_thread_fns</structname> structure
as the value of the <literal>optdata</literal> parameter.</para></sect2>
</sect1>
<sect1 id="bdajj"><title>POSIX Thread Client Application With Directory SDK
for C</title>
<indexterm>
<primary>C SDK</primary>
<secondary>POSIX threading</secondary>
</indexterm>
<para>The following example which uses <firstterm>pthreads</firstterm> (POSIX
threads) on Solaris systems, is the source code for a multithreaded client.
The client connects to a specified LDAP server. The client then creates several
threads to perform multiple search and update operations simultaneously on
the directory.</para>
<example id="pthread-example"><title>Using POSIX Threading on a Solaris System</title>
<programlisting>#include &lt;stdio.h>
#include &lt;malloc.h>
#include &lt;errno.h>
#include &lt;pthread.h>
#include &lt;synch.h>
#include "ldap.h"
/* Authentication and search information. */
#define NAME "cn=Directory Manager"
#define PASSWORD "rtfm11111"
#define BASE "dc=example,dc=com"
#define SCOPE LDAP_SCOPE_SUBTREE
/* Function declarations */
static void *search_thread();
static void *modify_thread();
static void *add_thread();
static void *delete_thread();
static void set_ld_error();
static int get_ld_error();
static void set_errno();
static int get_errno();
static void tsd_setup();
/* Linked list of LDAPMessage structs for search results. */
typedef struct ldapmsgwrapper {
LDAPMessage *lmw_messagep;
struct ldapmsgwrapper *lmw_next;
} ldapmsgwrapper;
LDAP *ld;
pthread_key_t key;
main( int argc, char **argv )
{
pthread_attr_t attr;
pthread_t search_tid, search_tid2, search_tid3, search_tid4;
pthread_t modify_tid, add_tid, delete_tid;
void *status;
struct ldap_thread_fns tfns;
struct ldap_extra_thread_fns extrafns;
int rc;
/* Check command-line syntax. */
if ( argc != 3 ) {
fprintf( stderr, "usage: %s &lt;host> &lt;port>\n", argv[0] );
exit( 1 );
}
/* Create a key. */
if ( pthread_key_create( &amp;key, free ) != 0 ) {
perror( "pthread_key_create" );
}
tsd_setup();
/* Initialize the LDAP session. Use prldap_init() for IPv6. */
if ( (ld = ldap_init( argv[1], atoi( argv[2] ) )) == NULL ) {
perror( "ldap_init" );
exit( 1 );
}
/* Set the function pointers for dealing with mutexes
and error information. */
memset( &amp;tfns, '\0', sizeof(struct ldap_thread_fns) );
tfns.ltf_mutex_alloc = (void *(*)(void)) my_mutex_alloc;
tfns.ltf_mutex_free = (void (*)(void *)) my_mutex_free;
tfns.ltf_mutex_lock = (int (*)(void *)) pthread_mutex_lock;
tfns.ltf_mutex_unlock = (int (*)(void *)) pthread_mutex_unlock;
tfns.ltf_get_errno = get_errno;
tfns.ltf_set_errno = set_errno;
tfns.ltf_get_lderrno = get_ld_error;
tfns.ltf_set_lderrno = set_ld_error;
tfns.ltf_lderrno_arg = NULL;
/* Set up this session to use those function pointers. */
rc = ldap_set_option( ld, LDAP_OPT_THREAD_FN_PTRS, (void *) &amp;tfns );
if ( rc &lt; 0 ) {
fprintf( stderr,
"ldap_set_option (LDAP_OPT_THREAD_FN_PTRS): %s\n",
ldap_err2string( rc ) );
exit( 1 );
}
/* Set the function pointers for working with semaphores. */
memset( &amp;extrafns, '\0', sizeof(struct ldap_extra_thread_fns) );
extrafns.ltf_mutex_trylock = (int (*)(void *)) = null;
extrafns.ltf_sema_alloc = (void *(*)(void)) = null;
extrafns.ltf_sema_free = (void (*)(void *)) = null;
extrafns.ltf_sema_wait = (int (*)(void *)) = null;
extrafns.ltf_sema_post = (int (*)(void *)) = null;
extrafns.ltf_threadid_fn = (void * (*)(void) )pthread_self;
/* Set up this session to use those function pointers. */
rc = ldap_set_option( ld,
LDAP_OPT_EXTRA_THREAD_FN_PTRS,
(void *) &amp;extrafns );
if ( rc &lt; 0 ) {
fprintf( stderr,
"ldap_set_option (LDAP_OPT_EXTRA_THREAD_FN_PTRS): %s\n",
ldap_err2string( rc ) );
exit( 1 );
}
/* Attempt to bind to the server. */
rc = ldap_simple_bind_s( ld, NAME, PASSWORD );
if ( rc != LDAP_SUCCESS ) {
fprintf( stderr, "ldap_simple_bind_s: %s\n", ldap_err2string( rc ) );
exit( 1 );
}
/* Initialize the attribute. */
if ( pthread_attr_init( &amp;attr ) != 0 ) {
perror( "pthread_attr_init" );
exit( 1 );
}
/* Specify that the threads are joinable. */
pthread_attr_setdetachstate( &amp;attr, PTHREAD_CREATE_JOINABLE );
/* Create seven threads: one for adding, one for modifying,
one for deleting, and four for searching. */
if (pthread_create(&amp;search_tid, &amp;attr, search_thread, "1") != 0) {
perror( "pthread_create search_thread" );
exit( 1 );
}
if (pthread_create(&amp;modify_tid, &amp;attr, modify_thread, "2") != 0) {
perror( "pthread_create modify_thread" );
exit( 1 );
}
if (pthread_create(&amp;search_tid2, &amp;attr, search_thread, "3") != 0) {
perror( "pthread_create search_thread2" );
exit( 1 );
}
if (pthread_create(&amp;add_tid, &amp;attr, add_thread, "4" ) != 0) {
perror( "pthread_create add_thread" );
exit( 1 );
}
if (pthread_create(&amp;search_tid3, &amp;attr, search_thread, "5") != 0) {
perror( "phread_create search_thread3" );
exit( 1 );
}
if (pthread_create(&amp;delete_tid, &amp;attr, delete_thread, "6") != 0) {
perror( "pthread_create delete_thread" );
exit( 1 );
}
if (pthread_create(&amp;search_tid4, &amp;attr, search_thread, "7") != 0) {
perror( "pthread_create search_thread4" );
exit( 1 );
}
/* Wait until these threads exit. */
pthread_join( modify_tid, &amp;status );
pthread_join( add_tid, &amp;status );
pthread_join( delete_tid, &amp;status );
pthread_join( search_tid, &amp;status );
pthread_join( search_tid2, &amp;status );
pthread_join( search_tid3, &amp;status );
pthread_join( search_tid4, &amp;status );
}
/* Thread for searching the directory.
The results are not printed out. */
static void *
search_thread( char *id )
{
LDAPMessage *res;
LDAPMessage *e;
char *a;
char **v;
char *dn;
BerElement *ber;
int i, rc, parse_rc, msgid, finished;
int num_entries, num_refs;
void *tsd;
struct timeval zerotime;
zerotime.tv_sec = zerotime.tv_usec = 0L;
printf( "Starting search_thread %s.\n", id );
tsd_setup();
/* Continually search the directory. */
for ( ;; ) {
printf( "Thread %s: Searching...\n", id );
finished = 0;
num_entries = 0;
num_refs = 0;
rc = ldap_search_ext( ld, BASE, SCOPE, "(objectclass=*)",
NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT, &amp;msgid );
if ( rc != LDAP_SUCCESS ) {
fprintf( stderr, "Thread %s error: ldap_search: %s\n",
id, ldap_err2string( rc ) );
continue;
}
/* Iterate through the results. In this example,
don't print out all the results. (It's easier
to see the output from the other threads this way.) */
while ( !finished ) {
rc = ldap_result( ld, msgid, LDAP_MSG_ONE, &amp;zerotime, &amp;res );
switch ( rc ) {
case -1:
rc = ldap_get_lderrno( ld, NULL, NULL );
fprintf( stderr, "ldap_result: %s\n", ldap_err2string( rc ) );
finished = 1;
break;
case 0:
break;
/* Keep track of the number of entries found. */
case LDAP_RES_SEARCH_ENTRY:
num_entries++;
break;
/* Keep track of the number of search references. */
case LDAP_RES_SEARCH_REFERENCE:
num_refs++;
break;
case LDAP_RES_SEARCH_RESULT:
finished = 1;
parse_rc = ldap_parse_result( ld, res, &amp;rc,
NULL, NULL, NULL, NULL, 1 );
if ( parse_rc != LDAP_SUCCESS ) {
fprintf( stderr,
"Thread %s error: can't parse result code.\n",
id );
break;
} else {
if ( rc != LDAP_SUCCESS ) {
fprintf( stderr,
"Thread %s error: ldap_search: %s\n",
id, ldap_err2string( rc ) );
} else {
printf( "Thread %s: Got %d results and %d references.\n",
id, num_entries, num_refs );
}
}
break;
default:
break;
}
}
}
}
/* Thread for modifying directory entries.
This thread searches for entries and randomly selects entries from
the search results for modification. */
static void *
modify_thread( char *id )
{
LDAPMessage *res;
LDAPMessage *e;
int i, modentry, num_entries, msgid, rc, parse_rc, finished;
LDAPMod mod;
LDAPMod *mods[2];
char *vals[2];
char *dn;
ldapmsgwrapper *list, *lmwp, *lastlmwp;
struct timeval zerotime;
zerotime.tv_sec = zerotime.tv_usec = 0L;
printf( "Starting modify_thread %s.\n", id );
tsd_setup();
rc = ldap_search_ext( ld, BASE, SCOPE, "(objectclass=*)",
NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT, &amp;msgid );
if ( rc != LDAP_SUCCESS ) {
fprintf( stderr, "Thread %s error: Modify thread: "
"ldap_search_ext: %s\n", id, ldap_err2string( rc ) );
exit( 1 );
}
list = lastlmwp = NULL;
finished = 0;
num_entries = 0;
while ( !finished ) {
rc = ldap_result( ld, msgid, LDAP_MSG_ONE, &amp;zerotime, &amp;res );
switch ( rc ) {
case -1:
rc = ldap_get_lderrno( ld, NULL, NULL );
fprintf( stderr, "ldap_result: %s\n", ldap_err2string( rc ) );
exit( 1 );
break;
case 0:
break;
/* Keep track of the number of entries found. */
case LDAP_RES_SEARCH_ENTRY:
num_entries++;
if (( lmwp = (ldapmsgwrapper *)
malloc( sizeof( ldapmsgwrapper ))) == NULL ) {
fprintf( stderr, "Thread %s: Modify thread: Cannot malloc\n", id );
exit( 1 );
}
lmwp->lmw_messagep = res;
lmwp->lmw_next = NULL;
if ( lastlmwp == NULL ) {
list = lastlmwp = lmwp;
} else {
lastlmwp->lmw_next = lmwp;
}
lastlmwp = lmwp;
break;
case LDAP_RES_SEARCH_REFERENCE:
break;
case LDAP_RES_SEARCH_RESULT:
finished = 1;
parse_rc = ldap_parse_result( ld, res, &amp;rc, NULL, NULL,
NULL, NULL, 1 );
if ( parse_rc != LDAP_SUCCESS ) {
fprintf( stderr,
"Thread %s error: can't parse result code.\n",
id );
exit( 1 );
} else {
if ( rc != LDAP_SUCCESS ) {
fprintf( stderr,
"Thread %s error: ldap_search: %s\n",
id, ldap_err2string( rc ) );
} else {
printf( "Thread %s: Got %d results.\n", id, num_entries );
}
}
break;
default:
break;
}
}
/* Set up the modifications to be made. */
mods[0] = &amp;mod;
mods[1] = NULL;
vals[0] = "bar";
vals[1] = NULL;
/* Modify randomly selected entries. */
for ( ;; ) {
/* Randomly select the entries. */
modentry = rand() % num_entries;
for ( i = 0, lmwp = list; lmwp != NULL &amp;&amp; i &lt; modentry;
i++, lmwp = lmwp->lmw_next ) {
/* Keep iterating. */
}
if ( lmwp == NULL ) {
fprintf( stderr,
"Thread %s: Modify thread could not find entry %d of %d\n",
id, modentry, num_entries );
continue;
}
e = lmwp->lmw_messagep;
printf( "Thread %s: Modify thread picked entry %d of %d\n",
id, i, num_entries );
/* Perform the modification. */
dn = ldap_get_dn( ld, e );
mod.mod_op = LDAP_MOD_REPLACE;
mod.mod_type = "description";
mod.mod_values = vals;
printf( "Thread %s: Modifying (%s)\n", id, dn );
rc = ldap_modify_ext_s( ld, dn, mods, NULL, NULL );
if ( rc != LDAP_SUCCESS ) {
rc = ldap_get_lderrno( ld, NULL, NULL );
fprintf( stderr, "ldap_modify_ext_s: %s\n", ldap_err2string( rc ) );
}
free( dn );
}
}
/* Thread for adding directory entries.
This thread randomly generates DNs for entries and attempts to
add them to the directory. */
static void *
add_thread( char *id )
{
LDAPMod mod[5];
LDAPMod *mods[6];
char dn[BUFSIZ], name[40];
char *cnvals[2], *snvals[2], *ocvals[3];
int i, rc;
printf( "Starting add_thread %s.\n", id );
tsd_setup();
/* Set up the entry to be added. */
for ( i = 0; i &lt; 5; i++ ) {
mods[i] = &amp;mod[i];
}
mods[5] = NULL;
mod[0].mod_op = 0;
mod[0].mod_type = "cn";
mod[0].mod_values = cnvals;
cnvals[1] = NULL;
mod[1].mod_op = 0;
mod[1].mod_type = "sn";
mod[1].mod_values = snvals;
snvals[1] = NULL;
mod[2].mod_op = 0;
mod[2].mod_type = "objectclass";
mod[2].mod_values = ocvals;
ocvals[0] = "top";
ocvals[1] = "person";
ocvals[2] = NULL;
mods[3] = NULL;
/* Randomly generate DNs and add entries. */
for ( ;; ) {
sprintf( name, "%d", rand() );
sprintf( dn, "cn=%s, " BASE, name );
cnvals[0] = name;
snvals[0] = name;
printf( "Thread %s: Adding entry (%s)\n", id, dn );
rc = ldap_add_ext_s( ld, dn, mods, NULL, NULL );
if ( rc != LDAP_SUCCESS ) {
rc = ldap_get_lderrno( ld, NULL, NULL );
fprintf( stderr, "ldap_add_ext_s: %s\n", ldap_err2string( rc ) );
}
}
}
/* Thread for deleting directory entries.
This thread randomly selects entries for deletion. */
static void *
delete_thread( char *id )
{
LDAPMessage *res;
char dn[BUFSIZ], name[40];
printf( "Starting delete_thread %s.\n", id );
tsd_setup();
/* Randomly select entries for deletion. */
for ( ;; ) {
sprintf( name, "%d", rand() );
sprintf( dn, "cn=%s, " BASE, name );
printf( "Thread %s: Deleting entry (%s)\n", id, dn );
if ( ldap_delete_ext_s( ld, dn, NULL, NULL ) != LDAP_SUCCESS ) {
ldap_perror( ld, "ldap_delete_ext_s" );
}
}
}
/* Function for allocating a mutex. */
static void *
my_mutex_alloc( void )
{
pthread_mutex_t *mutexp;
if ( (mutexp = malloc( sizeof(pthread_mutex_t) )) != NULL ) {
pthread_mutex_init( mutexp, NULL );
}
return( mutexp );
}
/* Function for freeing a mutex. */
static void
my_mutex_free( void *mutexp )
{
pthread_mutex_destroy( (pthread_mutex_t *) mutexp );
free( mutexp );
}
/* Error structure. */
struct ldap_error {
int le_errno;
char *le_matched;
char *le_errmsg;
};
/* Function to set up thread-specific data. */
static void
tsd_setup()
{
void *tsd;
tsd = pthread_getspecific( key );
if ( tsd != NULL ) {
fprintf( stderr, "tsd non-null!\n" );
pthread_exit( NULL );
}
tsd = (void *) calloc( 1, sizeof(struct ldap_error) );
pthread_setspecific( key, tsd );
}
/* Function for setting an LDAP error. */
static void
set_ld_error( int err, char *matched, char *errmsg, void *dummy )
{
struct ldap_error *le;
le = pthread_getspecific( key );
le->le_errno = err;
if ( le->le_matched != NULL ) {
ldap_memfree( le->le_matched );
}
le->le_matched = matched;
if ( le->le_errmsg != NULL ) {
ldap_memfree( le->le_errmsg );
}
le->le_errmsg = errmsg;
}
/* Function for getting an LDAP error. */
static int
get_ld_error( char **matched, char **errmsg, void *dummy )
{
struct ldap_error *le;
le = pthread_getspecific( key );
if ( matched != NULL ) {
*matched = le->le_matched;
}
if ( errmsg != NULL ) {
*errmsg = le->le_errmsg;
}
return( le->le_errno );
}
/* Function for setting errno. */
static void
set_errno( int err )
{
errno = err;
}
/* Function for getting errno. */
static int
get_errno( void )
{
return( errno );
}</programlisting>
</example>
</sect1>
</chapter>

View File

@@ -0,0 +1,171 @@
<!--
Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
Portions copyright 1999 Netscape Communications Corporation. All
Rights Reserved.
The contents of this document are subject to the terms of the
Creative Commons Attribution-ShareAlike 2.5 license or any later
version (the "License"). You may not use this document except in
compliance with the License.
See the License for the specific language governing
permissions and limitations under the License. You can obtain
a copy of the License at
http://creativecommons.org/licenses/by-sa/2.5/legalcode.
-->
<chapter id="csdk-quickstart"><title>Getting Started With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>quick start</secondary>
</indexterm><highlights>
<itemizedlist>
<para>This chapter shows how to start using &DirectorySDKForC;and covers
the following topics:</para>
<listitem><para><olink targetptr="bdabt">Sample Directory Client Code</olink></para>
</listitem>
<listitem><para><olink targetptr="bdabu">Compiling Directory SDK for C Client
Applications</olink></para></listitem>
<listitem><para><olink targetptr="bdabx">Running the Client</olink></para>
</listitem>
</itemizedlist>
</highlights>
<sect1 id="bdabt"><title>Sample Directory Client Code</title>
<indexterm>
<primary>example programs</primary>
<secondary>C SDK</secondary>
<tertiary>directory entry retrieval<?Pub Caret></tertiary>
</indexterm>
<para>The following sample source code is for a command-line program that
retrieves the full name, last name, email address, and telephone number of
Barbara Jensen.</para>
<example id="csdk-quick-sample"><title>Retrieving a Directory Entry</title>
<programlisting>#include &lt;stdio.h>
#include "ldap.h"
/* Adjust these setting for your own LDAP server */
#define HOSTNAME "localhost"
#define PORT_NUMBER LDAP_PORT
#define FIND_DN "uid=bjensen,ou=People,dc=example,dc=com"
int
main( int argc, char **argv )
{
LDAP *ld;
LDAPMessage *result, *e;
BerElement *ber;
char *a;
char **vals;
int i, rc;
/* Get a handle to an LDAP connection. */
/* To get the handle on an IPv6 network, use prldap_init() instead. */
if ( (ld = ldap_init( HOSTNAME, PORT_NUMBER )) == NULL ) {
perror( "ldap_init" );
return( 1 );
}
/* Bind anonymously to the LDAP server. */
rc = ldap_simple_bind_s( ld, NULL, NULL );
if ( rc != LDAP_SUCCESS ) {
fprintf(stderr, "ldap_simple_bind_s: %s\n", ldap_err2string(rc));
return( 1 );
}
/* Search for the entry. */
if ( ( rc = ldap_search_ext_s( ld, FIND_DN, LDAP_SCOPE_BASE,
"(objectclass=*)", NULL, 0, NULL, NULL, LDAP_NO_LIMIT,
LDAP_NO_LIMIT, &amp;result ) ) != LDAP_SUCCESS ) {
fprintf(stderr, "ldap_search_ext_s: %s\n", ldap_err2string(rc));
return( 1 );
}
/* Since we are doing a base search, there should be only
one matching entry. */
e = ldap_first_entry( ld, result );
if ( e != NULL ) {
printf( "\nFound %s:\n\n", FIND_DN );
/* Iterate through each attribute in the entry. */
for ( a = ldap_first_attribute( ld, e, &amp;ber );
a != NULL; a = ldap_next_attribute( ld, e, ber ) ) {
/* For each attribute, print the attribute name and values. */
if ((vals = ldap_get_values( ld, e, a)) != NULL ) {
for ( i = 0; vals[i] != NULL; i++ ) {
printf( "%s: %s\n", a, vals[i] );
}
ldap_value_free( vals );
}
ldap_memfree( a );
}
if ( ber != NULL ) {
ber_free( ber, 0 );
}
}
ldap_msgfree( result );
ldap_unbind( ld );
return( 0 );
}</programlisting>
</example>
</sect1>
<sect1 id="bdabu"><title>Compiling &DirectorySDKForC; Client Applications</title>
<indexterm>
<primary>C SDK</primary>
<secondary>compiling applications</secondary>
</indexterm>
<para>The method used to compile the source code depends on the operating
system on which you run the application. The following sections include instructions
for compiling on UNIX and Windows systems.</para>
<sect2 id="bdabv"><title>Compiling Programs on UNIX Systems</title>
<para>The &DirectorySDKForC; <filename>examples/</filename> directory contains
a UNIX <filename>Makefile</filename>. You can modify the <filename>Makefile</filename> to
compile the sample by adjusting the flags in the file. The <filename>Makefile</filename> assumes
that the &DirectorySDKForC; header files are located in the <filename>../include/
</filename> directory.</para></sect2>
<sect2 id="bdabw"><title>Compiling Programs on Windows Systems</title>
<itemizedlist>
<para>If you are compiling the sample client on Windows, set up the build
framework for this application. Make sure to do the following:</para>
<listitem><para>If you are using Microsoft development tools, create a new
project workspace for a console application. Then add the source file to the
project.</para></listitem>
<listitem><para>Set your options to include <filename>lib\</filename> as one
of the directories for library files, and <filename>include\</filename> as
one of the directories for include files.</para></listitem>
<listitem><para>Link to <filename>nsldap32v60.lib</filename>, the LDAP API
import library for Windows.</para></listitem>
</itemizedlist>
</sect2>
</sect1>
<sect1 id="bdabx"><title>Running the Client</title>
<para>Before running the sample client, make sure that your LDAP server is
set up with the entry the sample attempts to find. Unless you change the source
code in <olink targetptr="csdk-quick-sample">Example 5&ndash;1</olink>, the
entry would be for the full name, last name, email address, and telephone
number of Barbara Jensen.</para>
<sect2 id="bdaby"><title>Running Programs on UNIX Systems</title>
<para>If you have linked the client on a UNIX platform, the client requires
the SDK library file. Make sure to set your <envar>LD_LIBRARY_PATH</envar> to
locate the <filename>libldap60.so</filename> library file and its dependencies.</para>
<para>As an alternative, when linking the file, specify the option that identifies
the library directories that the runtime linker should search for. For example,
on Solaris systems use the <option>R</option> option to specify the location
of the <filename>libldap60.so</filename> file.</para></sect2>
<sect2 id="bdabz"><title>Running Programs on Windows Systems</title>
<para>If you have linked the client with the <filename>nsldap32v60.lib</filename> library
on a Windows system, copy the &DirectorySDKForC; DLL files to one of the
following directories:</para>
<itemizedlist>
<listitem><para>The directory where the application was loaded</para></listitem>
<listitem><para>The current directory</para></listitem>
<listitem><para>The Windows system directory, such as <filename>winnt\system32\</filename></para>
</listitem>
<listitem><para>The Windows directory</para></listitem>
<listitem><para>The directories listed in the <envar>PATH</envar> environment
variable</para></listitem>
</itemizedlist>
</sect2>
</sect1>
</chapter>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,222 @@
<!--
Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
Portions copyright 1999 Netscape Communications Corporation. All
Rights Reserved.
The contents of this document are subject to the terms of the
Creative Commons Attribution-ShareAlike 2.5 license or any later
version (the "License"). You may not use this document except in
compliance with the License.
See the License for the specific language governing
permissions and limitations under the License. You can obtain
a copy of the License at
http://creativecommons.org/licenses/by-sa/2.5/legalcode.
-->
<chapter id="csdk-sasl"><title>SASL Authentication With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>Simple Authentication and Security Layer (SASL)</secondary>
</indexterm><highlights>
<para>This chapter describes the process of using a Simple Authentication
and Security Layer (SASL) mechanism to authenticate an LDAP client to an LDAP
server.</para>
<itemizedlist>
<para>This chapter covers the following topics:</para>
<listitem><para><olink targetptr="bdaig">Understanding SASL and Directory
SDK for C</olink></para></listitem>
<listitem><para><olink targetptr="bdaih">Determining Supported SASL Mechanisms
With Directory SDK for C</olink></para></listitem>
<listitem><para><olink targetptr="bdaii">Authenticating Using SASL With Directory
SDK for C</olink></para></listitem>
</itemizedlist>
</highlights>
<sect1 id="bdaig"><title>Understanding SASL and &DirectorySDKForC;</title>
<para>The ability to authenticate to an LDAP server with a SASL mechanism
is a feature that is new to LDAP v3. LDAP v2 servers do not support this method
of authentication.</para>
<para>SASL is described in <ulink url="http://www.ietf.org/rfc/rfc4422.txt"
type="text_url"><?Pub Caret>RFC 4422</ulink>, <citetitle>Simple Authentication
and Security Layer (SASL)</citetitle>.</para></sect1>
<sect1 id="bdaih"><title>Determining Supported SASL Mechanisms With &DirectorySDKForC;
</title>
<para>To determine the SASL mechanisms supported by an LDAP v3 server, get
the root DSE of the server, and check the <literal>supportedSASLMechanisms</literal> attribute.
The values of this attribute are the names of the SASL mechanisms supported
by the server.</para>
<para>If the root DSE does not have a <literal>supportedSASLMechanisms</literal> attribute,
the server does not support any SASL mechanisms.</para>
<para>For information about getting the root DSE, see <olink targetptr="bdahv">To
Get the Root DSE</olink>.</para></sect1>
<sect1 id="bdaii"><title>Authenticating Using SASL With &DirectorySDKForC;</title>
<itemizedlist>
<para>To authenticate to the server with a SASL mechanism, call one of the
following:</para>
<listitem><para>The synchronous <function>ldap_sasl_bind_s</function> function</para>
</listitem>
<listitem><para>The asynchronous <function>ldap_sasl_bind</function> function</para>
<para>If you call the asynchronous function <function>ldap_sasl_bind</function>,
you need to call the <function>ldap_result</function> and <function>ldap_parse_sasl_bind_result
</function> functions to get the result of the SASL bind operation.</para>
</listitem>
</itemizedlist>
<para>Authentication with a SASL mechanism can take one or more round&mdash;trips
between your client and the server. The server might send a number of <firstterm>
challenges</firstterm> to the client. You might need to call <function>ldap_sasl_bind_s
</function> several times, or <function>ldap_sasl_bind</function>, <function>ldap_result
</function>, and <function>ldap_parse_sasl_bind_result</function> several
times in order to respond to each server challenge.</para>
<para>Before calling the function to perform a SASL bind operation, make sure
to specify that your client is LDAP v3 compliant. If you do not, an <errorcode>LDAP_NOT_SUPPORTED
</errorcode> result code is returned. See <olink targetptr="bdaci">Specifying
the LDAP Version of Your Client</olink>.</para>
<sect2 id="bdaij"><title>Synchronous SASL Bind Operation</title>
<para>If you want to wait for the results of the SASL bind operation to complete
before continuing, call the synchronous <function>ldap_sasl_bind_s</function> function.
This function sends a SASL bind request to the server. This function blocks
other work until the server sends the results of the operation back to your
client.</para>
<itemizedlist>
<para><function>ldap_sasl_bind_s</function> returns one of the following values:</para>
<listitem><para><errorcode>LDAP_SUCCESS</errorcode> if your client has successfully
authenticated.</para></listitem>
<listitem><para><errorcode>LDAP_SASL_BIND_IN_PROGRESS</errorcode> if the server
sends a challenge to your client. If you receive this result code, check the <literal>
servercredp</literal> argument for the <structname>berval</structname> structure
that contains the server&rsquo;s challenge. Call the <function>ldap_sasl_bind</function> function
again to send a response to that challenge.</para></listitem>
<listitem><para>An LDAP error code if a problem occurred or if authentication
failed. See the <olink targetptr="bdaux">ldap_sasl_bind_s</olink> function
documentation for a list of the possible result codes.</para></listitem>
</itemizedlist>
</sect2>
<sect2 id="bdaik"><title>Asynchronous SASL Bind Operation</title>
<para>If you want to perform other work in parallel while waiting for the
SASL bind operation to complete, use the following procedure.</para>
<task><title>To Bind Asynchronously Over SASL</title>
<procedure>
<step><para>Call the asynchronous <function>ldap_sasl_bind</function> function
to send an LDAP SASL bind request.</para><para>This function returns an <errorcode>
LDAP_SUCCESS</errorcode> result code if the request was successfully sent,
or an LDAP result code if an error occurred while sending the request. The
function also sets the <literal>msgidp</literal> argument to point to a message
ID identifying the SASL bind operation.</para></step>
<step><para>Call the <function>ldap_result</function> function, passing in
this message ID to determine whether the server sent a response for this operation
to your client.</para><para>The <function>ldap_result</function> function
uses the message ID to determine if the server sent a SASL bind response.
The function passes back the response in an <structname>LDAPMessage</structname> structure.
</para></step>
<step><para>Call the <function>ldap_parse_sasl_bind_result</function> function
to parse the <structname>LDAPMessage</structname> structure and retrieve information
from the server&rsquo;s response.</para><para>If the server sent a challenge
to your client, the challenge is specified in the <structname>berval</structname> structure
passed back as the <literal>servercredp</literal> argument.</para></step>
<step><para>Call the <function>ldap_get_lderrno</function> function to get
the LDAP result code for the operation.</para>
<itemizedlist>
<para>The function can return one of the following values:</para>
<listitem><para><errorcode>LDAP_SUCCESS</errorcode> if your client successfully
authenticated to the server.</para></listitem>
<listitem><para><errorcode>LDAP_SASL_BIND_IN_PROGRESS</errorcode> if the server
sent a challenge to your client.</para><para>If the server returned an <errorcode>
LDAP_SASL_BIND_IN_PROGRESS</errorcode> result code, check the <literal>servercredp
</literal> argument for the <structname>berval</structname> structure that
contains the server&rsquo;s challenge.</para></listitem>
<listitem><para>An LDAP error code if a problem occurred or if authentication
failed.</para><para>See the <function>ldap_sasl_bind</function> function documentation
for a list of result codes that the server can return for this operation.</para>
</listitem>
</itemizedlist>
</step>
<step><para>If the result code is <errorcode>LDAP_SASL_BIND_IN_PROGRESS</errorcode> and
if the server passed back another challenge, determine the response to that
challenge by calling the <function>ldap_sasl_bind</function> function again
to send that response to the server.</para><para>You can call <function>ldap_result
</function> and <function>ldap_parse_sasl_bind_result</function> again to
get the next challenge sent from the server, if the result is again <errorcode>LDAP_SASL_BIND_IN_PROGRESS
</errorcode>.</para></step>
</procedure>
<example>
<title>Authenticating Over SASL</title>
<para>This example shows an LDAP client that authenticates using the SASL
mechanism that is named <literal>babsmechanism</literal>.</para>
<programlisting>#include &lt;stdio.h>
#include &lt;stdlib.h>
#include &lt;string.h>
#include &lt;time.h>
#include "ldap.h"
int
main( int argc, char **argv )
{
LDAP *ld;
LDAPMod mod0;
LDAPMod mod1;
LDAPMod *mods[ 3 ];
char *vals0[ 2 ];
char *vals1[ 2 ];
time_t now;
char buf[ 128 ];
struct berval cred;
struct berval *servcred;
int version;
/* Get a handle to an LDAP connection. Use prldap_init() for IPv6. */
if ( (ld = ldap_init( "localhost", 389 )) == NULL ) {
perror( "ldap_init" );
return( 1 );
}
/* Set the LDAP protocol version supported by the client
to 3. (By default, this is set to 2. SASL authentication
is part of version 3 of the LDAP protocol.) */
version = LDAP_VERSION3;
ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &amp;version );
/* authenticate */
cred.bv_val = "magic";
cred.bv_len = sizeof( "magic" ) - 1;
if ( ldap_sasl_bind_s( ld, "uid=bjensen,ou=people,dc=example,dc=com",
"babsmechanism", &amp;cred, NULL, NULL,
&amp;servcred ) != LDAP_SUCCESS ) {
ldap_perror( ld, "ldap_sasl_bind_s" );
return( 1 );
}
/* get and print the credentials returned by the server */
printf( "Server credentials: %s\n", servcred->bv_val );
/* construct the list of modifications to make */
mod0.mod_op = LDAP_MOD_REPLACE;
mod0.mod_type = "mail";
vals0[0] = "babs@example.com";
vals0[1] = NULL;
mod0.mod_values = vals0;
mod1.mod_op = LDAP_MOD_ADD;
mod1.mod_type = "description";
time( &amp;now );
sprintf( buf, "This entry was modified with the modattrs program on %s",
ctime( &amp;now ));
/* Get rid of \n which ctime put on the end of the time string */
if ( buf[ strlen( buf ) - 1 ] == '\n' ) {
buf[ strlen( buf ) - 1 ] = '\0';
}
vals1[ 0 ] = buf;
vals1[ 1 ] = NULL;
mod1.mod_values = vals1;
mods[ 0 ] = &amp;mod0;
mods[ 1 ] = &amp;mod1;
mods[ 2 ] = NULL;
/* make the change */
if ( ldap_modify_s(ld, "uid=bjensen,ou=people,dc=example,dc=com", mods)
!= LDAP_SUCCESS ) {
ldap_perror( ld, "ldap_modify_s" );
return( 1 );
}
ldap_unbind( ld );
printf( "modification was successful\n" );
return( 0 );
}</programlisting>
</example>
</task>
</sect2>
</sect1>
</chapter>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,374 @@
<!--
Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
Portions copyright 1999 Netscape Communications Corporation. All
Rights Reserved.
The contents of this document are subject to the terms of the
Creative Commons Attribution-ShareAlike 2.5 license or any later
version (the "License"). You may not use this document except in
compliance with the License.
See the License for the specific language governing
permissions and limitations under the License. You can obtain
a copy of the License at
http://creativecommons.org/licenses/by-sa/2.5/legalcode.
-->
<chapter id="csdk-server-info"><title>Getting Server Information With &DirectorySDKForC;
</title>
<indexterm>
<primary>C SDK</primary>
<secondary>getting server information</secondary>
</indexterm><highlights>
<para>This chapter explains how to access and modify information about your
LDAP server over the LDAP protocol.</para>
<itemizedlist>
<para>This chapter covers the following topics:</para>
<listitem><para><olink targetptr="bdahu">Reading DSEs With Directory SDK for
C</olink></para></listitem>
<listitem><para><olink targetptr="bdahw">Determining LDAP v3 Support With
Directory SDK for C</olink></para></listitem>
<listitem><para><olink targetptr="bdahx">Getting Schema Information With Directory
SDK for C</olink></para></listitem>
</itemizedlist>
</highlights>
<sect1 id="bdahu"><title>Reading DSEs With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>getting server information</secondary>
<tertiary>DSE</tertiary>
</indexterm>
<para>A DSA-specific entry, <firstterm>DSE</firstterm>, contains information
specific to the server. In a directory tree, the root of the tree is the root
DSE. The root DSE is not part of any naming context. For example, the root
DSE is superior to <literal>dc=example,dc=com</literal> in the directory tree.</para>
<para>The root DSE is specified as part of LDAP v3. Note that LDAP v2 servers
do not necessarily have a root DSE.</para>
<itemizedlist>
<para>The root DSE can contain the following information:</para>
<listitem><para>The naming contexts of this server such as, <literal>dc=example,dc=com
</literal></para></listitem>
<listitem><para>URLs of alternate servers to contact if this server is unavailable
</para></listitem>
<listitem><para>The versions of LDAP supported by this server, version 2 or
version 3</para></listitem>
<listitem><para>The LDAP v3 controls supported by the server</para><para>See <olink targetptr="csdk-controls">Chapter&nbsp;16, LDAP Controls With Directory SDK
for C</olink> for details.</para></listitem>
<listitem><para>The SASL mechanisms supported by the server</para><para>See <olink targetptr="csdk-sasl">Chapter&nbsp;17, SASL Authentication With Directory
SDK for C</olink> for details.</para></listitem>
<listitem><para>The LDAP v3 extended operations supported by the server</para>
<para>See <olink targetptr="csdk-extop">Chapter&nbsp;18, Extended Operations
With Directory SDK for C</olink> for details.</para></listitem>
</itemizedlist>
<para>The following lists root DSE attributes and explains the meaning of
their values.</para>
<table frame="topbot" pgwide="1" id="server-root-dse-info"><title>Root DSE
Attributes and Descriptions of Their Values</title>
<tgroup cols="2"><colspec colnum="1" colwidth="21.64*"><colspec colnum="2"
colwidth="78.36*">
<thead>
<row>
<entry>
<para>Attribute Name</para></entry>
<entry>
<para>Description of Values</para></entry>
</row>
</thead>
<tbody>
<row>
<entry>
<para><literal>namingContexts</literal></para></entry>
<entry>
<para>The naming contexts supported by this server, such <literal>dc=example,dc=com
</literal>.</para></entry>
</row>
<row>
<entry>
<para><literal>altServer</literal></para></entry>
<entry>
<para>LDAP URLs that identify other servers to contact if this server is unavailable.
</para></entry>
</row>
<row>
<entry>
<para><literal>supportedExtension</literal></para></entry>
<entry>
<para>The object identifiers (OIDs) of the LDAP v3 extended operations supported
by this server.</para>
<para>If this attribute is not in the root DSE, the server does not support
any extended operations.</para></entry>
</row>
<row>
<entry>
<para><literal>supportedControl</literal></para></entry>
<entry>
<para>The OIDs of the LDAP v3 controls supported by this server.</para>
<para>If this attribute is not in the root DSE, the server does not support
any LDAP v3 controls.</para></entry>
</row>
<row>
<entry>
<para><literal>supportedSASLMechanisms</literal></para></entry>
<entry>
<para>The names of the SASL mechanisms supported by the server.</para>
<para>If this attribute is not in the root DSE, the server does not support
any SASL mechanisms.</para></entry>
</row>
<row>
<entry>
<para><literal>supportedLDAPVersion</literal></para></entry>
<entry>
<para>The value of this attribute is the version of LDAP supported by this
server, such as <literal>2</literal> or <literal>3</literal>.</para></entry>
</row>
</tbody>
</tgroup>
</table>
<task id="bdahv"><title>To Get the Root DSE</title>
<procedure>
<step><para>Initialize an LDAP session by calling the <function>ldap_init</function> or <function>
prldap_init</function> function.</para></step>
<step><para>Turn off automatic referral handling by calling the <function>ldap_set_option
</function> function and setting the <literal>LDAP_OPT_REFERRALS</literal> option
to <literal>LDAP_OPT_OFF</literal>.</para></step>
<step><para>Search the directory with the following criteria:</para>
<substeps>
<step><para>Set the search scope to a <literal>base</literal> search.</para>
</step>
<step><para>Specify an empty string for the base DN.</para></step>
<step><para>Use the search filter <literal>(objectclass=*)</literal>.</para>
</step></substeps>
</step>
<step><para>Check the results of the search.</para><para>If the server returns
a result code, such as <errorcode>LDAP_OPERATIONS_ERROR</errorcode>, <errorcode>LDAP_PROTOCOL_ERROR
</errorcode>, <errorcode>LDAP_REFERRAL</errorcode>, or <errorcode>LDAP_NO_SUCH_OBJECT
</errorcode>, the LDAP server probably does not support LDAP v3.</para><para>The
following example gets the root DSE for a server and prints the values of
the root DSE attributes. The function assumes that you are passing in a valid
connection handle, an <structname>LDAP</structname> structure, you have created
by calling <function>ldap_init</function> or <function>prldap_init</function>.
The function returns <literal>0</literal> if successful or <literal>1</literal> if
an error occurred.</para></step>
</procedure>
<example id="server-dse-attr-example">
<title>Getting the Root DSE and Printing its Attribute Values</title>
<programlisting>int printdse( LDAP *ld )
{
int rc, i;
char *matched_msg = NULL, *error_msg = NULL;
LDAPMessage *result, *e;
BerElement *ber;
char *a;
char **vals;
char *attrs[3];
/* Verify that the connection handle is valid. */
if ( ld == NULL ) {
fprintf( stderr, "Invalid connection handle.\n" );
return( 1 );
}
/* Set automatic referral processing off. */
if ( ldap_set_option( ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF ) != 0 ) {
rc = ldap_get_lderrno( ld, NULL, NULL );
fprintf( stderr, "ldap_set_option: %s\n", ldap_err2string( rc ) );
return( 1 );
}
/* Search for the root DSE. */
attrs[0] = "supportedControl";
attrs[1] = "supportedExtension";
attrs[2] = NULL;
rc = ldap_search_ext_s( ld, "", LDAP_SCOPE_BASE, "(objectclass=*)",
attrs, 0, NULL, NULL, NULL, 0, &amp;result );
/* Check the search results. */
switch( rc ) {
/* If successful, the root DSE was found. */
case LDAP_SUCCESS:
break;
/* If the root DSE was not found, the server does not comply
with the LDAPv3 protocol. */
case LDAP_PARTIAL_RESULTS:
case LDAP_NO_SUCH_OBJECT:
case LDAP_OPERATIONS_ERROR:
case LDAP_PROTOCOL_ERROR:
printf( "LDAP server returned result code %d (%s).\n"
"This server does not support the LDAPv3 protocol.\n",
rc, ldap_err2string( rc ) );
return( 1 );
/* If any other value is returned, an error must have occurred. */
default:
fprintf( stderr, "ldap_search_ext_s: %s\n", ldap_err2string( rc ) );
return( 1 );
}
/* Since only one entry should have matched, get that entry. */
e = ldap_first_entry( ld, result );
if ( e == NULL ) {
fprintf( stderr, "ldap_search_ext_s: Unable to get root DSE.\n");
ldap_memfree( result );
return( 1 );
}
/* Iterate through each attribute in the entry. */
for ( a = ldap_first_attribute( ld, e, &amp;ber );
a != NULL; a = ldap_next_attribute( ld, e, ber ) ) {
/* Print each value of the attribute. */
if ((vals = ldap_get_values( ld, e, a)) != NULL ) {
for ( i = 0; vals[i] != NULL; i++ ) {
printf( "%s: %s\n", a, vals[i] );
}
/* Free memory allocated by ldap_get_values(). */
ldap_value_free( vals );
}
/* Free memory allocated by ldap_first_attribute(). */
ldap_memfree( a );
}
/* Free memory allocated by ldap_first_attribute(). */
if ( ber != NULL ) {
ber_free( ber, 0 );
}
printf( "\n" );
/* Free memory allocated by ldap_search_ext_s(). */
ldap_msgfree( result );
ldap_unbind( ld );
return( 0 );
}</programlisting>
</example>
</task>
</sect1>
<sect1 id="bdahw"><title>Determining LDAP v3 Support With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>getting server information</secondary>
<tertiary>LDAP v3 support</tertiary>
</indexterm>
<para>You can determine what version an LDAP server supports by getting the <literal>
supportedLDAPVersion</literal> attribute from the root DSE. This attribute
could contain the value <literal>2</literal> or <literal>3</literal>.</para>
<para>You do not need to authenticate or bind before searching the directory.
Unlike LDAP v2, LDAP v3 states that clients do not need to bind to the server
before performing LDAP operations.</para>
<para>The following example connects to an LDAP server. The example code then
determines whether the server supports LDAP v3.</para>
<example id="server-ldapv3-support-example"><title>Determining the Supported
LDAP Version</title>
<programlisting>/* Function for determining if the LDAP server supports LDAPv3.
This function returns 1 if the server supports LDAPv3 or
0 if the server does not support LDAPv3.
*/
int
check_version( char *hostname, int portnum )
{
LDAP *ld;
int i, rc, v3supported = 0;
LDAPMessage *result, *e;
BerElement *ber;
LDAPControl **serverctrls = NULL, **clntctrls = NULL;
char *a, *dn;
char **vals;
char *attrs[2];
char *filter = "(objectClass=*)";
/* Check arguments */
if ( !hostname || !hostname[0] || !portnum ) {
printf( "Error: hostname or port number not specified\n" );
return( -1 );
}
/* Get a handle to an LDAP connection. Use prldap_init() for IPv6. */
if ( (ld = ldap_init( hostname, portnum )) == NULL ) {
perror( "ldap_init" );
return( -1 );
}
/* Set automatic referral processing off. */
if ( ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF) !=
LDAP_SUCCESS) {
ldap_perror( ld, "ldap_set_option" );
return( -1 );
}
/* Search for the root DSE and get the supportedLDAPVersion attribute. */
attrs[0] = "supportedLDAPVersion";
attrs[1] = NULL;
rc = ldap_search_ext_s( ld, "", LDAP_SCOPE_BASE, filter, attrs, 0,
serverctrls, clntctrls, NULL, 0, &amp;result );
/* Check the search results. */
switch( rc ) {
/* If successful, the root DSE was found. */
case LDAP_SUCCESS:
break;
/* If the root DSE was not found, the server does not comply
with the LDAPv3 protocol. */
case LDAP_PARTIAL_RESULTS:
case LDAP_NO_SUCH_OBJECT:
case LDAP_OPERATIONS_ERROR:
case LDAP_PROTOCOL_ERROR:
ldap_perror( ld, "ldap_search_ext_s" );
return( 0 );
break;
/* If an different result code is returned, an error may have
occurred (for example, the server may be down. */
default:
ldap_perror( ld, "ldap_search_ext_s" );
return( -1 );
break;
}
/* Get the values of the supportedLDAPVersion attribute in the entry. */
if (( e = ldap_first_entry( ld, result )) != NULL &amp;&amp;
( a = ldap_first_attribute( ld, e, &amp;ber )) != NULL &amp;&amp;
(vals = ldap_get_values( ld, e, a)) != NULL ) {
for ( i = 0; vals[i] != NULL; i++ ) {
if ( !strcmp( "3", vals[i] ) ) {
v3supported = 1;
break;
}
}
/* Free any memory allocated. */
ldap_value_free( vals );
ldap_memfree( a );
if ( ber != NULL ) {
ber_free( ber, 0 );
}
}
/* Free memory allocated by ldap_search_ext_s(). */
ldap_msgfree( result );
/* Free the ld structure. */
ldap_unbind_s( ld );
/* Return a value indicating whether or not LDAPv3 is supported. */
return( v3supported );
}
...</programlisting>
</example>
</sect1>
<sect1 id="bdahx"><title>Getting Schema Information With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>getting server information</secondary>
<tertiary>schema</tertiary>
</indexterm>
<para>In LDAP v3, an entry can specify the schema that defines the object
classes, attributes, and matching rules used by the directory. This entry
is called the <literal>subschema</literal> entry. To find the DN of the <literal>
subschema</literal> entry, get the <literal>subschemaSubentry</literal> operational
attribute from the root DSE or any entry.</para>
<itemizedlist>
<para>The <literal>subschema</literal> entry can have the following attributes:</para>
<listitem><para><literal>objectClasses</literal> specifies the object class
definitions in the schema. Each value of this attribute is an object class
that is known to the server.</para></listitem>
<listitem><para><literal>attributeTypes</literal> specifies the attribute
type definitions in the schema. Each value of this attribute is an attribute
type that is known to the server.</para></listitem>
<listitem><para><literal>matchingRules</literal> specifies the matching rule
definitions in the schema. Each value of this attribute is a matching rule
that is known to the server.</para></listitem>
<listitem><para><literal>matchingRuleUse</literal> specifies the use of a
matching rule in the schema. This rule specifies the attributes that can be
used with this extensible matching rule. Each value of this attribute is a
matching rule use description.</para></listitem>
</itemizedlist>
<para>For information about the format of the attribute values, see <ulink
url="http://www.ietf.org/rfc/rfc4517.txt" type="text_url"><?Pub Caret>RFC
4517</ulink>, <citetitle>Lightweight Directory Access Protocol (v3): Attribute
Syntax Definitions</citetitle>.</para></sect1>
</chapter>

View File

@@ -0,0 +1,382 @@
<!--
Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
Portions copyright 1999 Netscape Communications Corporation. All
Rights Reserved.
The contents of this document are subject to the terms of the
Creative Commons Attribution-ShareAlike 2.5 license or any later
version (the "License"). You may not use this document except in
compliance with the License.
See the License for the specific language governing
permissions and limitations under the License. You can obtain
a copy of the License at
http://creativecommons.org/licenses/by-sa/2.5/legalcode.
-->
<chapter id="csdk-ssl"><title>SSL Connections With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>Secure Sockets Layer (SSL)</secondary>
</indexterm><highlights>
<para>This chapter describes the process of enabling an LDAP client to connect
to an LDAP server over the Secure Sockets Layer (SSL) protocol.</para>
<itemizedlist>
<para>This chapter covers the following topics:</para>
<listitem><para><olink targetptr="bdahz">How SSL Works With Directory SDK
for C</olink></para></listitem>
<listitem><para><olink targetptr="bdaia">Connecting to a Server Over SSL With
Directory SDK for C</olink></para></listitem>
<listitem><para><olink targetptr="bdaic">Handling Errors With Directory SDK
for C</olink></para></listitem>
<listitem><para><olink targetptr="ssl-start-tls">Starting Transport Layer
Security With Directory SDK for C</olink></para></listitem>
<listitem><para><olink targetptr="bdaid">Installing Your Own SSL I/O Functions
With Directory SDK for C</olink></para></listitem>
<listitem><para><olink targetptr="bdaie">Using Certificate-Based Client Authentication
With Directory SDK for C</olink></para></listitem>
</itemizedlist>
</highlights>
<sect1 id="bdahz"><title>How SSL Works With &DirectorySDKForC;</title>
<para>The primary goal of the SSL protocol is to provide privacy and reliability
between two communicating applications.</para>
<note><para>SSL is not supported on all LDAP servers.</para><para>SSL communication
must take place on a separate TCP port unless the server supports Start TLS.</para>
</note>
<para>When an LDAP client connects to an LDAP server over SSL, the server
identifies itself by sending a certificate to the client. The client needs
to determine whether or not the certificate authority (CA) that issued the
certificate is trusted. The client therefore searches a certificate database
for the certificate of the CA. If the client cannot find the certificate,
the client refuses to connect to the server. If the certificate is marked <firstterm>
not trusted</firstterm>, the client also refuses to connect to the server.</para>
<para>The LDAP server can also request that the client send a certificate
to authenticate itself. This part of the process is called <firstterm>certificate-based
client authentication</firstterm>. If the client receives a request for a
certificate from the server, the client retrieves its certificate from the
certificate database. The client sends the certificate to the server for authentication.
After receiving the client&rsquo;s certificate, the LDAP server determines
whether or not the CA that issued the certificate is trusted. If the server
cannot find the CA certificate in the certificate database, the server refuses
to authenticate the client. If the CA certificate is marked as <firstterm>not
trusted</firstterm>, the server also refuses to authenticate the client. If
the CA is trusted, the server uses the certificate subject name to determine
whether the client has access to perform the requested operation.</para>
<itemizedlist>
<para>&DirectorySDKForC; includes functions that allow you to connect an
LDAP client to an LDAP server over SSL. The functions make the following assumptions:
</para>
<listitem><para>Your client has access to a certificate database. The function
call uses this certificate database to determine if the client can trust the
certificate sent from the server.</para><para>Different certificate database
versions can be incompatible, which might result in database errors.</para>
</listitem>
<listitem>
<itemizedlist>
<para>The database used contains any one of the following:</para>
<listitem><para>The certificate of the CA that issued the server&rsquo;s certificate
</para></listitem>
<listitem><para>If the CAs are organized in a hierarchy, the certificate of
any of the CAs in the hierarchy</para></listitem>
<listitem><para>The certificate of the LDAP server</para></listitem>
</itemizedlist>
</listitem>
<listitem><para>The CA certificate is marked as <firstterm>trusted</firstterm> in
the certificate database.</para></listitem>
<listitem>
<itemizedlist>
<para>If you plan to use certificate-based client authentication, you also
need the following:</para>
<listitem><para>A client certificate in the certificate database issued by
a CA that is trusted by the LDAP server</para></listitem>
<listitem><para>A public-private key pair in a key file</para></listitem>
</itemizedlist>
</listitem>
</itemizedlist>
<itemizedlist>
<para>The functions allow you to do the following:</para>
<listitem><para>Set the session option for communicating with the server over
SSL.</para><para>See <olink targetptr="bdaia">Connecting to a Server Over
SSL With Directory SDK for C</olink> for details.</para></listitem>
<listitem><para>Start transport layer security by using the Start TLS extended
operation</para><para>See <olink targetptr="ssl-start-tls">Starting Transport
Layer Security With Directory SDK for C</olink> for details.</para></listitem>
<listitem><para>Replace the default I/O functions with your own I/O functions
for communicating over SSL</para><para>See <olink targetptr="bdaid">Installing
Your Own SSL I/O Functions With Directory SDK for C</olink> for details.</para>
</listitem>
<listitem><para>Enable your client to send certificates to authenticate itself</para>
<para>See <olink targetptr="bdaie">Using Certificate-Based Client Authentication
With Directory SDK for C</olink> for details.</para></listitem>
</itemizedlist>
</sect1>
<sect1 id="bdaia"><title>Connecting to a Server Over SSL With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>Secure Sockets Layer (SSL)</secondary>
<tertiary>connecting to the server</tertiary>
</indexterm>
<para>To enable your LDAP client to connect to an LDAP server with SSL, you
need to perform the following procedure.</para>
<task><title>To Initialize a Client SSL Connection by Using <function>ldapssl_init
</function></title>
<procedure>
<step><para>Initialize your client by calling one of the following functions:</para>
<substeps>
<step><para>Call <function>ldapssl_client_init</function> if you do not plan
to use certificate-based client authentication.</para></step>
<step><para>Call <function>ldapssl_clientauth_init</function> if you plan
to use certificate-based client authentication.</para></step>
<step><para>Call <function>ldapssl_advclientauth_init</function>.</para><para>If
you use certificate-based client authentication, you need to specify the path
of the security module database, or to specify the method to verify the server
certificate.</para></step></substeps>
<para>You must initialize your client before initializing the LDAP session.
The process of initializing the client opens the certificate database.</para>
</step>
<step><para>Initialize an LDAP session with the secure server by calling the <function>
ldapssl_init</function> function.</para><para>For an alternative way to accomplish
this step, see <olink targetptr="bdaib">Alternative to ldapssl_init</olink>.</para>
</step>
</procedure>
<example id="ssl-init-connection-example">
<title>To Initialize a Client SSL Connection by using <function>ldapssl_init</function></title>
<para>This example initializes a client to connect to a secure LDAP server
over SSL.</para>
<programlisting>if ( ldapssl_client_init( "/local/examples/alias/", NULL ) &lt; 0) {
printf( "Failed to initialize SSL client...\n" );
return( 1 );
}
/* get a handle to an LDAP connection */
if ( (ld = ldapssl_init( "cert.example.com", LDAPS_PORT, 1 )) == NULL {
perror( "ldapssl_init" );
return( 1 );
}
...
/* Client can now perform LDAP operations on the secure LDAP server. */
...</programlisting>
</example>
</task>
<sect2 id="bdaib"><title>Alternative to <function>ldapssl_init</function></title>
<para>As an alternative to calling the <function>ldapssl_init</function> function,
you can use the following procedure.</para>
<task><title>To Initialize a Client SSL Connection (Alternative Method Using <function>
ldap_init</function></title>
<procedure>
<step><para>After initializing your client, initialize an LDAP session with
the server by calling the standard initialization function <function>ldap_init</function>.
</para></step>
<step><para>Install the standard SSL I/O functions by calling <function>ldapssl_install_routines
</function>.</para></step>
<step><para>Set the SSL option in the LDAP structure by calling <function>ldap_set_option
</function>.</para></step>
</procedure>
<example id="ssl-init-alt-connection-example">
<title>Initializing a Client SSL Initialization (Alternative Method Using <function>
ldap_init</function>)</title>
<para>This example prepares a client to connect to a secure LDAP server over
SSL using <function>ldap_init</function>.</para>
<programlisting>if ( ldapssl_client_init( "/local/examples/alias/", NULL ) &lt; 0) {
printf( "Failed to initialize SSL client...\n" );
return( 1 );
}
/* Initialize LDAP session. Use prldap_init() for IPv6. */
if ( (ld = ldap_init( MY_HOST, LDAPS_PORT )) == NULL ) {
perror( "ldap_init" );
return( 1 );
}
/* Load SSL routines */
if ( ldapssl_install_routines( ld ) != 0 ) {
ldap_perror( ld, "ldapssl_install_routines" );
return( 1 );
}
/* Set up option in LDAP struct for using SSL */
if ( ldap_set_option( ld, LDAP_OPT_SSL, LDAP_OPT_ON ) != 0 ) {
ldap_perror( ld, "ldap_set_option" );
return( 1 );
}
/* Client can now perform LDAP operations on the secure LDAP server. */
...</programlisting>
</example>
</task>
</sect2>
</sect1>
<sect1 id="bdaic"><title>Handling Errors With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>Secure Sockets Layer (SSL)</secondary>
<tertiary>handling errors</tertiary>
</indexterm>
<para>After calling any of the SSL initialization functions, you can convert
SSL-specific error codes to text strings by calling <function>ldapssl_err2string</function>.
The <function>ldapssl_err2string</function> function provides support for
special SSL error messages that are not handled by the normal error conversion
routine <function>ldap_err2string</function>. </para></sect1>
<sect1 id="ssl-start-tls"><title>Starting Transport Layer Security With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>Secure Sockets Layer (SSL)</secondary>
<tertiary>start TLS</tertiary>
</indexterm>
<para><ulink url="http://www.ietf.org/rfc/rfc4513.txt" type="text_url">RFC
4513</ulink>, <citetitle>Lightweight Directory Access Protocol (LDAP): Authentication
Methods and Security Mechanisms</citetitle>, describes the extended operation.
Start TLS allows you to connect to a nonsecure port, and then request transport
layer security.</para>
<task><title>To Use Start TLS</title>
<procedure>
<step><para>Initialize your client with <function>ldapssl_client_init</function>.
</para><para>The process of initializing the client opens the certificate
database.</para></step>
<step><para>Get a handle to an LDAP connection.</para></step>
<step><para>Request Start TLS with <function>ldap_start_tls_s</function>.</para>
</step>
<step><para>Authenticate to the directory to perform additional operations.</para>
</step>
</procedure>
<example>
<title>Using Start TLS</title>
<para>This example connects and uses Start TLS, then requests the Who am I?
extended operation. The example relies on a certificate database directory, <filename
class="directory">/local/examples/alias/</filename>.</para>
<programlisting>/*
* Use the Start TLS extended operation.
*/
#include "examples.h"
#include &lt;ldap_ssl.h>
/*
* Path to certificate database for SSL
*/
#define CERT_DB_PATH "/local/examples/alias/"
int
main( int argc, char **argv )
{
int version;
LDAP *ld;
int rc;
char *authzid;
/* Initialize access to the certificate database. */
if ( ldapssl_client_init( CERT_DB_PATH, NULL ) != 0 ) {
fprintf( stderr, "ldapssl_client_init failed\n" );
fprintf( stderr, "certificate database path: %s\n", CERT_DB_PATH );
return( 1 );
}
/* Use LDAPv3. */
version = LDAP_VERSION3;
if ( ldap_set_option( NULL, LDAP_OPT_PROTOCOL_VERSION, &amp;version )
!= 0 ) {
fprintf( stderr,
"ldap_set_option protocol version to %d failed\n",
version );
return( 1 );
}
/* Get a handle to an LDAP connection. Use prldap_init() for IPv6. */
if ( (ld = ldap_init( MY_HOST, MY_PORT )) == NULL ) {
perror( "ldap_init" );
return( 1 );
}
/* Request Start TLS. */
if ( ldap_start_tls_s( ld, NULL, NULL ) != LDAP_SUCCESS ) {
ldap_perror( ld, "ldap_start_tls_s" );
return( 1 );
}
printf( "Start TLS operation successful.\n" );
/* Authenticate to the directory. */
if ( ldap_simple_bind_s( ld, ENTRYDN, ENTRYPW ) != LDAP_SUCCESS ) {
ldap_perror( ld, "ldap_simple_bind_s" );
return( 1 );
}
/* Examine my authorization ID. */
if ( (rc = ldap_whoami_s( ld, NULL, NULL, &amp;authzid ) )
!= LDAP_SUCCESS ) {
fprintf( stderr, "ldap_whoami_s: %s\n", ldap_err2string( rc ) );
ldap_unbind( ld );
return( 1 );
}
printf( "Authorization ID: %s\n", authzid );
ldap_unbind( ld );
return( 0 );
}</programlisting>
<para>See <olink targetptr="extendop-whoami">Performing a Who Am I? Extended
Operation With Directory SDK for C</olink> for details on using the &ldquo;Who
am I?&rdquo; extended operation.</para></example>
<taskrelated role="troubleshooting">
<para>To troubleshoot Start TLS problems, call the <function>PR_GetError</function> function.
This function gives you access to many Network Security Services (NSS) errors
further documented in the <ulink
url="http://www.mozilla.org/projects/security/pki/nss/ref/ssl/sslerr.html"
type="text_url">Mozilla.org SSL Reference</ulink>.</para></taskrelated>
</task>
</sect1>
<sect1 id="bdaid"><title>Installing Your Own SSL I/O Functions With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>Secure Sockets Layer (SSL)</secondary>
<tertiary>custom I/O functions</tertiary>
</indexterm>
<para>The <function>ldapssl_init</function> and <function>ldapssl_install_routines
</function> functions both set up the session to use the standard SSL I/O
functions provided with &DirectorySDKForC;. If you want to use your own
SSL I/O functions, use the <structname>ldap_x_ext_io_fns</structname> structure.</para>
<task><title>To Install Your Own SSL I/O Functions</title>
<procedure>
<step><para>Create an <structname>ldap_x_ext_io_fns</structname> structure,
and set the fields to point to your I/O functions.</para></step>
<step><para>Call <function>ldap_set_option</function> to point to that structure.
</para>
<programlisting>if (ldap_set_option( ld, LDAP_X_OPT_EXTIO_FN_PTRS, &amp;my_io_struct) != 0 ) {
ldap_perror( ld, "ldap_set_option" );
return( 1 );
}</programlisting>
</step>
</procedure>
</task>
</sect1>
<sect1 id="bdaie"><title>Using Certificate-Based Client Authentication With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>Secure Sockets Layer (SSL)</secondary>
<tertiary>certificate-based authentication</tertiary>
</indexterm>
<para>Some LDAP servers can be configured to use certificate-based client
authentication. The server requests that your client send a certificate to
identify itself. Use the following procedure to configure your client to use
certificates for authentication.</para>
<task><title>To Use Certificate-Based Client Authentication</title>
<procedure>
<step><para>Initialize your LDAP client by calling either <function>ldapssl_clientauth_init
</function> or <function>ldapssl_advclientauth_init</function>, not <function>ldapssl_client_init
</function>.</para><para>U<?Pub Caret1>se <function>ldapssl_advclientauth_init</function> if
you want to specify the path of a security module database, or to specify
the method used to verify the server certificate.</para><para>You can use
one of these functions to initialize your client even if you do not plan to
use certificate-based client authentication. The functions are equivalent
to <function>ldapssl_client_init</function>.</para></step>
<step><para>Initialize an LDAP session with the secure server by calling <function>
ldapssl_init</function>.</para></step>
<step><para>Enable your client to authenticate with the secure server by calling <function>
ldapssl_enable_clientauth</function>.</para></step>
<step><para>Perform a Simple Authentication and Security Layer (SASL) bind
operation by using the mechanism <literal>EXTERNAL</literal>. This mechanism
indicates to the directory server that certificates should be used to authenticate
clients.</para><para>With &cnDirectoryServer;, if you perform a SASL bind
operation, but the server cannot find the corresponding directory entry for
a client certificate, the server returns an <literal>LDAP_INVALID_CREDENTIALS</literal> result
code with the error message <literal>Client Certificate Mapping Failed</literal>.
</para></step>
</procedure>
</task>
</sect1>
</chapter>

View File

@@ -0,0 +1,970 @@
<!--
Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
Portions copyright 1999 Netscape Communications Corporation. All
Rights Reserved.
The contents of this document are subject to the terms of the
Creative Commons Attribution-ShareAlike 2.5 license or any later
version (the "License"). You may not use this document except in
compliance with the License.
See the License for the specific language governing
permissions and limitations under the License. You can obtain
a copy of the License at
http://creativecommons.org/licenses/by-sa/2.5/legalcode.
-->
<chapter id="csdk-using"><title>About &DirectorySDKForC;</title>
<highlights>
<itemizedlist>
<para>This chapter introduces &DirectorySDKForC; and covers the following
topics:</para>
<listitem><para><olink targetptr="bdaas">Overview of Directory SDK for C</olink></para>
</listitem>
<listitem><para><olink targetptr="bdaaw">Files Provided With Directory SDK
for C</olink></para></listitem>
<listitem><para><olink targetptr="bdabi">Compiling Applications with Directory
SDK for C</olink></para></listitem>
<listitem><para><olink targetptr="bdabp">Sample Programs for Directory SDK
for C</olink></para></listitem>
</itemizedlist>
</highlights>
<sect1 id="bdaas"><title>Overview of &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>overview of</secondary>
</indexterm>
<para>&DirectorySDKForC; includes the C libraries for the LDAP API as well
as sample code that demonstrates how to call many functions. The APIs are
defined by the header files that declare all of the functions, data types,
and code values in the SDK. You use the functions in this API to write C or
C++ client applications that take full advantage of server capabilities.</para>
<para>The APIs are built around core functions of the LDAP v2 and v3 standards.
Therefore, the APIs can be used to interact with any conforming LDAP server.
This API conforms to the standard that is proposed in <citetitle>The C LDAP
Application Programming Interface</citetitle>.</para>
<sect2 id="bdaat"><title>LDAP API</title>
<indexterm>
<primary>LDAP Application Programming Interface (API)</primary>
<see>LDAP API</see></indexterm><indexterm>
<primary>LDAP API</primary>
</indexterm><indexterm>
<primary>APIs</primary>
<secondary>LDAP</secondary>
</indexterm>
<para><ulink url="http://www.ietf.org/rfc/rfc4511.txt" type="text_url">RFC
4511</ulink>, <citetitle>Lightweight Directory Access Protocol (v3)</citetitle>,
defines a set of operations to access data in an LDAP v3 compliant directory
server. The functionality implemented in &DirectorySDKForC; closely follows
these operations because a C API is defined for each operation.</para>
<itemizedlist>
<para>With the C API, you can enable client applications to connect to LDAP
v3 compliant directory servers. Client applications can then perform both
standard and extended LDAP operations such as the following:</para>
<listitem><para>Search for and retrieve a list of entries.</para></listitem>
<listitem><para>Add new entries to the database.</para></listitem>
<listitem><para>Update existing directory entries.</para></listitem>
<listitem><para>Delete entries.</para></listitem>
<listitem><para>Rename entries.</para><para>For example, if you are writing
an email application, you can use the functions in the API to retrieve email
addresses from an LDAP server.</para></listitem>
</itemizedlist>
</sect2>
<sect2 id="bdaau"><title>Synchronous and Asynchronous Operations</title>
<indexterm>
<primary>C SDK</primary>
<secondary>synchronous functions</secondary>
</indexterm><indexterm>
<primary>C SDK</primary>
<secondary>asynchronous functions</secondary>
</indexterm><indexterm>
<primary>operations</primary>
<secondary>asynchronous</secondary>
</indexterm><indexterm>
<primary>operations</primary>
<secondary>synchronous</secondary>
</indexterm>
<para>The API functions allow you to perform LDAP operations synchronously
or asynchronously. The only differences between these two options are in the
calling convention. The LDAP exchanges are identical.</para>
<itemizedlist>
<listitem><para>Call a synchronous function to wait for the operation to complete
before receiving the return value of a function.</para></listitem>
<listitem><para>Call an asynchronous function to perform other work while
waiting for an operation to complete. Your application must then poll for
results.</para><para>For more information, see <olink targetptr="bdabq">Synchronous
Examples</olink>, and <olink targetptr="bdabr">Asynchronous Examples</olink>.<?Pub
Caret></para></listitem>
</itemizedlist>
</sect2>
</sect1>
<sect1 id="bdaaw"><title>Files Provided With Directory SDK for C</title>
<indexterm>
<primary>C SDK</primary>
<secondary>files installed</secondary>
</indexterm>
<para>&DirectorySDKForC; includes a number of sample files, headers, libraries,
and tools. This section helps you to locate the files. All locations are relative
to the directory where the software is installed, which depends on your operating
system.</para>
<table frame="topbot" pgwide="1"><title>&DirectorySDKForC; Content</title>
<tgroup cols="2"><colspec colnum="1" colwidth="19.69*"><colspec colnum="2"
colwidth="80.31*">
<thead>
<row>
<entry>
<para>Directory Location</para></entry>
<entry>
<para>Description</para></entry>
</row>
</thead>
<tbody>
<row>
<entry>
<para><filename>etc/</filename></para></entry>
<entry>
<para>Contains miscellaneous files for you to use. The files are described
in <olink targetptr="bdabc">Miscellaneous Files</olink></para></entry>
</row>
<row>
<entry>
<para><filename>examples/</filename></para></entry>
<entry>
<para>Contains sample source code and Makefiles for LDAP clients. See the <literal>
README</literal> file in this directory for more information.</para></entry>
</row>
<row>
<entry>
<para><filename>include/</filename></para></entry>
<entry>
<para>Contains the header files. You must include the files in this directory
in your client source files. The header files are described in <olink targetptr="bdaax">Directory SDK for C Header Files</olink></para></entry>
</row>
<row>
<entry>
<para><filename>include-nspr/</filename></para></entry>
<entry>
<para>Contains Netscape Portable Runtime (NSPR) header files. NSPR provides
a platform-neutral API for system&mdash;level and <literal>libc</literal>&mdash;style
functions.</para></entry>
</row>
<row>
<entry>
<para><filename>include-private/</filename></para></entry>
<entry>
<para>Contains private header files that are not documented in this guide.</para>
</entry>
</row>
<row>
<entry>
<para><filename>lib/</filename></para></entry>
<entry>
<para>Contains the C library files. The specific library used is dependent
on the type of application you are building. For details see <olink targetptr="bdabd">Directory SDK for C Libraries</olink>.</para></entry>
</row>
<row>
<entry>
<para><filename>lib-private/</filename></para></entry>
<entry>
<para>Contains private libraries that are not documented in this guide.</para>
</entry>
</row>
<row>
<entry>
<para><filename>tools/</filename></para></entry>
<entry>
<para>Contains the LDAP command-line tools. To use these applications, you
must ensure that the tools can find the LDAP API shared library or dynamic
link library.</para></entry>
</row>
</tbody>
</tgroup>
</table>
<sect2 id="bdaax"><title>&DirectorySDKForC; Header Files</title>
<indexterm>
<primary>C SDK</primary>
<secondary>header files</secondary>
</indexterm><indexterm>
<primary>header files</primary>
<secondary>C SDK</secondary>
</indexterm>
<para>The following table describes &DirectorySDKForC; header files that
are in the <filename>include/</filename> directory. </para>
<note><para>All locations are relative to the directory where the software
is installed, which depends on your operating system.</para></note>
<table frame="topbot" pgwide="1" id="csdk-headers"><title>&DirectorySDKForC; Header
Files</title>
<tgroup cols="2"><colspec colnum="1" colwidth="22.89*"><colspec colnum="2"
colwidth="77.11*">
<thead>
<row>
<entry>
<para>Header File</para></entry>
<entry>
<para>Description</para></entry>
</row>
</thead>
<tbody>
<row>
<entry>
<para><filename>disptmpl.h</filename></para></entry>
<entry>
<para>A header file related to the templates (<literal>ldaptemplates.conf</literal>).
</para></entry>
</row>
<row>
<entry>
<para><literal>lber.h</literal></para></entry>
<entry>
<para>Contains prototypes for the standard Basic Encoding Rules (BER) functions,
structures, and defines. For details see <olink targetptr="bdaaz">lber.h Header
File</olink></para></entry>
</row>
<row>
<entry>
<para><filename>ldap-deprecated.h</filename></para></entry>
<entry>
<para>Contains deprecated functions that should not be used. This header is
included in <filename>ldap.h</filename>.</para></entry>
</row>
<row>
<entry>
<para><filename>ldap-extension.h</filename></para></entry>
<entry>
<para>Contains functions, structures, and defines that extend the standard
LDAP C API specification. This header is included in <filename>ldap.h</filename>.
</para></entry>
</row>
<row>
<entry>
<para><filename>ldap-platform.h</filename></para></entry>
<entry>
<para>A private header file that contains platform-specific definitions, which
allow abstraction from the underlying system.</para></entry>
</row>
<row>
<entry>
<para><filename>ldap-standard.h</filename></para></entry>
<entry>
<para>Contains the standard LDAP functions, structures, and defines. This
header is included in <filename>ldap.h</filename>.</para></entry>
</row>
<row>
<entry>
<para><filename>ldap-to-be-deprecated.h</filename></para></entry>
<entry>
<para>Contains functions, structures, and defines that might be deprecated
in future releases. This header is included in <filename>ldap.h</filename>.</para>
</entry>
</row>
<row>
<entry>
<para><filename>ldap.h</filename></para></entry>
<entry>
<para>This base header contains LDAP functions, structures, and defines to
mirror the latest LDAP C API specifications.</para>
<itemizedlist>
<para>This header also includes the following header files:</para>
<listitem><para><filename>ldap-deprecated.h</filename></para></listitem>
<listitem><para><filename>ldap-extension.h</filename></para></listitem>
<listitem><para><filename>ldap-standard.h</filename></para></listitem>
<listitem><para><filename>ldap-to-be-deprecated.h</filename></para></listitem>
</itemizedlist>
<para>For details, see <olink targetptr="bdaay">ldap.h Header File</olink>.</para>
</entry>
</row>
<row>
<entry>
<para><filename>ldap_ssl.h</filename></para></entry>
<entry colsep="0">
<para>Contains prototypes for LDAP over SSL functions, structures, and defines.
For details, see <olink targetptr="bdaba">ldap_ssl.h Header File</olink></para>
</entry>
</row>
<row>
<entry>
<para><filename>ldappr.h</filename></para></entry>
<entry>
<para>Contains prototypes for the functions, structures, and defines that
are contained in the Netscape Portable Runtime (NSPR) API. For details see<olink targetptr="bdabb">ldappr.h Header File</olink></para></entry>
</row>
<row>
<entry>
<para><filename>srchpref.h</filename></para></entry>
<entry>
<para>A header file related to the search preferences (<filename>ldapsearchprefs.conf
</filename> ).</para></entry>
</row>
</tbody>
</tgroup>
</table>
<sect3 id="bdaay"><title><filename>ldap.h</filename> Header File</title>
<para><indexterm>
<primary><filename>ldap.h</filename> header file</primary>
<secondary>including</secondary>
</indexterm>To make use of the &DirectorySDKForC; functions, include the <filename>
ldap.h</filename> header file in your C source files as shown in this line
of code:</para>
<programlisting>#include "ldap.h"</programlisting>
<itemizedlist>
<para>By including this file, you also include the following header files:</para>
<listitem><para><filename>ldap-deprecated.h</filename></para></listitem>
<listitem><para><filename>ldap-extension.h</filename></para></listitem>
<listitem><para><filename>ldap-standard.h</filename></para></listitem>
<listitem><para><filename>ldap-platform.h</filename></para></listitem>
<listitem><para><filename>ldap-to-be-deprecated.h</filename></para></listitem>
</itemizedlist>
</sect3>
<sect3 id="bdaaz"><title><filename>lber.h</filename> Header File</title>
<indexterm>
<primary><filename>lber.h</filename> header file</primary>
<secondary>including</secondary>
</indexterm>
<para><filename>lber.h</filename> is included in <filename>ldap-standard.h</filename>.
You do not need to include the header explicitly. Basic Encoding Rules (BER)
is a simple tag-value scheme to encode requests and decode results.</para>
</sect3>
<sect3 id="bdaba"><title><filename>ldap_ssl.h</filename> Header File</title>
<para><indexterm>
<primary><filename>ldap_ssl.h</filename> header file</primary>
<secondary>including</secondary>
</indexterm>If you are calling LDAP over SSL functions, you also need to include
the <filename>ldap_ssl.h</filename> header file, as follows:</para>
<programlisting>#include "ldap_ssl.h"</programlisting>
</sect3>
<sect3 id="bdabb"><title><filename>ldappr.h</filename> Header File</title>
<indexterm>
<primary><filename>ldappr.h</filename> header file</primary>
<secondary>including</secondary>
</indexterm>
<para>To make use of the Netscape Portable Runtime (NSPR) API with your LDAP
applications, you must include the <filename>ldappr.h</filename> file. The
NSPR is a set of platform-neutral APIs that provides system functions such
as threads, thread synchronization, I/O, interval timing, and atomic operations.
This header file contains prototypes for functions that tie the LDAP libraries
to NSPR. You include the header file as follows:</para>
<programlisting>#include "ldappr.h"</programlisting>
<para>For more information about NSPR, see the <literal>ldappr.h</literal> header
file and the Netscape Portable Runtime project page at <ulink
url="
http://www.mozilla.org/projects/nspr/" type="text_url">http://www.mozilla.org/projects/nspr/
</ulink>.</para></sect3>
</sect2>
<sect2 id="bdabc"><title>Miscellaneous Files</title>
<indexterm>
<primary><filename>ldapfilter.conf</filename>sample file</primary>
</indexterm><indexterm>
<primary><filename>ldapfriendly</filename>sample file</primary>
</indexterm><indexterm>
<primary><filename>ldapsearchprefs.conf</filename>sample file</primary>
</indexterm><indexterm>
<primary><filename>ldaptemplates.conf</filename>sample file</primary>
</indexterm><indexterm>
<primary>C SDK</primary>
<secondary>sample files</secondary>
</indexterm>
<para>&DirectorySDKForC; includes the sample files described in the following
table. Sample files can be retrieved when using certain APIs. Sample files
are located in the <filename>etc/</filename> directory. All locations are
relative to the directory where the software is installed, which depends on
your operating system.</para>
<table frame="topbot" pgwide="1" id="csdk-sample-config"><title>Sample Configuration
Files</title>
<tgroup cols="2"><colspec colnum="1" colwidth="24.27*"><colspec colnum="2"
colwidth="75.73*">
<thead>
<row>
<entry>
<para>File Name</para></entry>
<entry>
<para>Description</para></entry>
</row>
</thead>
<tbody>
<row>
<entry>
<para><filename>ldapfilter.conf</filename></para></entry>
<entry>
<para>This filter configuration file can be used in context with <function>ldap_init_getfilter
</function>.</para></entry>
</row>
<row>
<entry>
<para><filename>ldapfriendly</filename></para></entry>
<entry>
<para>This file is used to map the two&mdash;letter country codes to their
full names by <function>ldap_friendly_name</function>.</para></entry>
</row>
<row>
<entry>
<para><filename>ldapsearchprefs.conf</filename></para></entry>
<entry>
<para>This configuration file was used in context with a deprecated function.</para>
</entry>
</row>
<row>
<entry>
<para><filename>ldaptemplates.conf</filename></para></entry>
<entry>
<para>This configuration file was used in context with a deprecated function.</para>
</entry>
</row>
</tbody>
</tgroup>
</table>
</sect2>
<sect2 id="bdabd"><title>&DirectorySDKForC; Libraries</title>
<indexterm>
<primary>C SDK</primary>
<secondary>libraries</secondary>
</indexterm><indexterm>
<primary>libraries</primary>
<secondary>C SDK</secondary>
</indexterm>
<para>&DirectorySDKForC; includes several different libraries. A library
is a set of ready-made functions that are linked into a program. &DirectorySDKForC; uses <firstterm>
shared</firstterm> libraries. Shared libraries are dynamically loaded into
memory when needed, reducing the size of the executable.</para>
<sect3 id="bdabe"><title>Library Naming Conventions</title>
<para>Libraries on different systems have different naming conventions. The
following table shows the&DirectorySDKForC; naming conventions.</para>
<table frame="topbot" pgwide="1" id="csdk-naming-conventions"><title>Library
Naming Convention by Operating System</title>
<tgroup cols="3">
<?PubTbl tgroup dispwid="712.00px">
<colspec colnum="1" colwidth="25.72*"><colspec colnum="2" colwidth="28.14*">
<colspec colnum="3" colwidth="46.13*">
<thead>
<row>
<entry>
<para>Operating System</para></entry>
<entry>
<para>Static Library Name</para></entry>
<entry>
<para>Shared Library Name</para></entry>
</row>
</thead>
<tbody>
<row>
<entry>
<para>Solaris and Red Hat systems</para></entry>
<entry>
<para><filename>lib<replaceable>libraryname</replaceable>.a</filename></para>
</entry>
<entry>
<para><filename>lib<replaceable>libraryname</replaceable>.so.<replaceable>versionnumber
</replaceable></filename></para></entry>
</row>
<row>
<entry>
<para>HP-UX systems</para></entry>
<entry>
<para><filename>lib<replaceable>libraryname</replaceable>.a</filename></para>
</entry>
<entry>
<para><filename>lib<replaceable>libraryname</replaceable>.sl</filename></para>
</entry>
</row>
<row>
<entry>
<para>Windows systems</para></entry>
<entry>
<para><filename>ns<replaceable>libraryname</replaceable>.lib</filename></para>
</entry>
<entry>
<para><filename>ns<replaceable>libraryname</replaceable>.dll</filename></para>
</entry>
</row>
</tbody>
</tgroup>
</table>
<para>On <trademark class="registered">UNIX</trademark> systems, the shared
library file name can be fully qualified by prefixing path information.</para>
</sect3>
<sect3 id="bdabf"><title>Installed Shared Libraries</title>
<para>The following table describes the installed libraries that are in the <filename>
lib/</filename> directory. All locations are relative to the directory where
the software is installed, which depends on your operating system.</para>
<table frame="topbot" pgwide="1" id="csdk-shared-libs"><title>Shared Libraries</title>
<tgroup cols="3"><colspec colnum="1" colwidth="17.02*"><colspec colnum="2"
colwidth="18.77*"><colspec colnum="3" colwidth="64.22*">
<thead>
<row>
<entry>
<para>UNIX Library</para></entry>
<entry>
<para>Windows Library</para></entry>
<entry>
<para>Description</para></entry>
</row>
</thead>
<tbody>
<row>
<entry>
<para><filename>libldap60.so</filename></para></entry>
<entry>
<para><filename>nsldap32v60.dll</filename></para></entry>
<entry>
<para>LDAP library.</para></entry>
</row>
<row>
<entry>
<para><literal>libprldap60.so</literal></para></entry>
<entry>
<para><literal>nsldappr32v60.dll</literal></para></entry>
<entry>
<para>LDAP library built with NSPR.</para>
<para>This library requires the <filename>libnspr4.so</filename> library in
the <filename>lib-private/</filename> directory.</para></entry>
</row>
<row>
<entry>
<para><literal>libssldap60.so</literal></para></entry>
<entry>
<para><literal>nsldapssl32v60.dll</literal></para></entry>
<entry>
<para>LDAP library that is built with support for the Secure Sockets Layer
protocol.</para>
<para>This library depends on the <filename>libnss3.so</filename> and <filename>libnspr4.so
</filename> libraries in the <filename>lib-private/</filename> directory.</para>
</entry>
</row>
</tbody>
</tgroup>
</table>
</sect3>
<sect3 id="bdabg"><title>&DirectorySDKForC; Dependencies</title>
<itemizedlist>
<para>&DirectorySDKForC; resolves dependencies for the following APIs at
run&mdash;time:</para>
<listitem><para>Netscape Portable Runtime (NSPR) provides core cross-platform
functions.</para></listitem>
<listitem><para>Netscape Security Services (NSS) provides encryption, cryptographic,
Secure Sockets Layer (SSL), and Public Key Infrastructure (PKI) support.</para>
</listitem>
<listitem><para>Simple Authentication and Security Layer (SASL) provides support
for applications that require SASL.</para></listitem>
</itemizedlist>
</sect3>
</sect2>
<sect2 id="bdabh"><title>LDAP Tools</title>
<indexterm>
<primary>LDAP tools</primary>
</indexterm>
<para>&DirectorySDKForC; includes several utilities to help you work with
LDAP data sets. These utilities are installed in the <filename>tools/</filename> directory.
For details on each tool described in the following table, see the corresponding
man pages. A list of options can be retrieved by typing the tool name at the
command line.</para>
<table frame="topbot" pgwide="1" id="csdk-tools"><title>&DirectorySDKForC; LDAP
Tools</title>
<tgroup cols="2"><colspec colnum="1" colwidth="13.45*"><colspec colnum="2"
colwidth="86.55*">
<thead>
<row>
<entry>
<para>Command</para></entry>
<entry>
<para>Description</para></entry>
</row>
</thead>
<tbody>
<row>
<entry>
<para><command>ldapcmp</command></para></entry>
<entry>
<para>Compares the contents of a single LDAP entry or subtree in two directories.
</para></entry>
</row>
<row>
<entry>
<para><command>ldapcompare</command></para></entry>
<entry>
<para>Compares an attribute value against the contents of a given LDAP entry.</para>
</entry>
</row>
<row>
<entry>
<para><command>ldapdelete</command></para></entry>
<entry>
<para>Deletes existing LDAP entries.</para></entry>
</row>
<row>
<entry>
<para><command>ldapmodify</command></para></entry>
<entry>
<para>Edits the contents of an LDAP directory, either by adding new entries
or modifying existing ones.</para></entry>
</row>
<row>
<entry>
<para><command>ldappasswd</command></para></entry>
<entry>
<para>Changes user passwords on LDAP entries.</para></entry>
</row>
<row>
<entry>
<para><command>ldapsearch</command></para></entry>
<entry>
<para>Issues search requests to an LDAP directory, then displays the result
as LDAP Data Interchange Format (LDIF) text.</para></entry>
</row>
</tbody>
</tgroup>
</table>
</sect2>
</sect1>
<sect1 id="bdabi"><title>Compiling Applications with Directory SDK for C</title>
<indexterm>
<primary>C SDK</primary>
<secondary>compiling applications</secondary>
</indexterm>
<para>When compiling applications, you must include the header files and link
to the libraries required. Information about including the header files is
in <olink targetptr="bdaax">Directory SDK for C Header Files</olink>. Linking
to shared libraries is covered in this section. &DirectorySDKForC; is qualified
to work with C compilers.</para>
<caution><para>&DirectorySDKForC; is not guaranteed to work with C++ compilers.
</para></caution>
<sect2 id="bdabj"><title>Compiling on UNIX Platforms</title>
<para>When compiling clients on UNIX platforms, specify link options correctly
to link the application to the appropriate shared libraries. See the <filename>Makefile
</filename> in the <filename>examples/</filename> directory for details on
compiling your applications on UNIX platforms.</para></sect2>
<sect2 id="bdabk"><title>Compiling on Windows Systems With &DirectorySDKForC;</title>
<itemizedlist>
<para>A Windows application can use either a command-line interface or a graphical
user interface (GUI). Windows systems refer to a console application. In a
console application, all user interaction happens through the command shell
interface, with a <structname>FILE</structname> pointer as found in UNIX systems.
Given this difference, make sure that you define the following:</para>
<listitem><para><literal>_CONSOLE</literal> if you are writing a console application
</para></listitem>
<listitem><para><literal>_WINDOWS</literal> if you are writing a standard
Windows GUI application</para></listitem>
</itemizedlist>
</sect2>
<sect2 id="bdabo"><title>Linking Dependencies</title>
<indexterm>
<primary>libraries</primary>
<secondary>runtime</secondary>
</indexterm>
<para>When you run LDAP clients, you must ensure that the operating system
can find the shared libraries that support the functions called by your application.
Generally, these files are referred to as <emphasis>runtime</emphasis> libraries.
Any of the following options ensure that the operating system can find the
shared libraries.</para>
<itemizedlist>
<listitem><para>Make sure that the shared library file, such as <filename>libldap60.so
</filename>, is in a location specified by environment variables.</para>
</listitem>
<listitem><para>On some platforms, clients can be complied with flags that
let you set the runtime path to load libraries as an environment variable.</para>
<itemizedlist>
<listitem><para>On <trademark>Solaris</trademark> and Red Hat systems, you
can use the <envar>LD_LIBRARY_PATH</envar> environment variable if you use
the <literal>-Wl,+s+b</literal> flag when compiling and linking.</para>
</listitem>
<listitem><para>On HP-UX system, use the <envar>SHLIB_PATH</envar> environment
variable.</para></listitem>
<listitem>
<orderedlist>
<para>On Windows systems, copy all dynamic link libraries (DLLs) needed for
your application to a directory where your client can find the libraries.
Other software might install a different version of the DLLs in the Windows <filename>
system32\</filename> directory. Make sure that your client finds the DLLs
included with &DirectorySDKForC; before your client finds the version in
the <filename>system32\</filename> directory. At runtime, your client searches
for the DLL in the following locations in the order shown:</para>
<listitem><para>The directory from which the application loaded</para>
</listitem>
<listitem><para>The current directory</para></listitem>
<listitem><para>The Windows system directory, typically <filename>winnt\system32\
</filename></para><para>To avoid potential conflicts, do not copy the DLL
to this directory</para></listitem>
<listitem><para>The directories listed in the <envar>PATH</envar> environment
variable</para></listitem>
</orderedlist>
</listitem>
</itemizedlist>
</listitem>
<listitem><para>Use a link flag that specifies the path where the executable
can find the library. For example, on Solaris systems, you can use the <literal>-R
</literal> flag to specify the path where the executable can find the library.</para>
<para>See the <filename>Makefile</filename> in the <filename>examples/</filename> directory
for examples of additional settings for compiling and linking your LDAP client.
Different platforms might require different sets of define statements.</para>
</listitem>
</itemizedlist>
</sect2>
</sect1>
<sect1 id="bdabp"><title>Sample Programs for Directory SDK for C</title>
<indexterm>
<primary>C SDK</primary>
<secondary>sample programs</secondary>
</indexterm><indexterm>
<primary>example programs</primary>
<secondary>C SDK</secondary>
</indexterm>
<para>&DirectorySDKForC; includes several examples that demonstrate the
use of the functions that the SDK provides. The examples are located in the <filename>
examples/</filename> directory. The example code is designed to run against
the LDAP v3 compliant &cnDirectoryServer;. Furthermore, the example code is
designed to work with sample data that has been properly loaded. For details
on the source files, refer to the <filename>README</filename> in the <filename>examples/
</filename> directory.</para>
<para>The samples use synchronous LDAP calls and their asynchronous counterparts.
Because synchronous LDAP calls are more straightforward than their asynchronous
counterparts, look at the synchronous examples first.</para>
<sect2 id="bdabq"><title>Synchronous Examples</title>
<indexterm>
<primary>C SDK</primary>
<secondary>synchronous examples</secondary>
</indexterm><indexterm>
<primary>example programs</primary>
<secondary>C SDK</secondary>
<tertiary>synchronous</tertiary>
</indexterm>
<para>The synchronous calls block the calling process until all results have
been returned. As these programs usually rely on event loops, the programs
are not appropriate for use with clients that implement a GUI in a single-threaded
environment. However, these sample programs do work with command-line clients
and CGI programs.</para>
<table frame="topbot" pgwide="1" id="csdk-sync-examples"><title>Synchronous
Example Programs</title>
<tgroup cols="2"><colspec colnum="1" colwidth="18.17*"><colspec colnum="2"
colwidth="81.83*">
<thead>
<row>
<entry>
<para>Example Source</para></entry>
<entry>
<para>Description</para></entry>
</row>
</thead>
<tbody>
<row>
<entry>
<para><filename>authzid.c</filename></para></entry>
<entry>
<para>Shows how to use the authorization ID control, which allows you to get
the authorization ID for an LDAP operation.</para></entry>
</row>
<row>
<entry>
<para><filename>compare.c</filename></para></entry>
<entry>
<para>Shows how to use <function>ldap_compare_s</function>, which allows you
to test if a particular value is contained in an attribute of an entry.</para>
</entry>
</row>
<row>
<entry>
<para><filename>crtfilt.c</filename></para></entry>
<entry>
<para>Shows how to use the <function>ldap_create_filter</function> function
to generate LDAP filters.</para></entry>
</row>
<row>
<entry>
<para><filename>csearch.c</filename></para></entry>
<entry>
<para>Like <filename>search.c</filename>, but enables an in-memory cache.</para>
</entry>
</row>
<row>
<entry>
<para><filename>effright.c</filename></para></entry>
<entry>
<para>Shows how to use the get effective rights control, which allows you
to determine access rights to entries and their attributes.</para></entry>
</row>
<row>
<entry>
<para><filename>getattrs.c</filename></para></entry>
<entry>
<para>Retrieves specific attributes from an entry.</para></entry>
</row>
<row>
<entry>
<para><filename>getfilt.c</filename></para></entry>
<entry>
<para>Shows how to use the <function>ldap_getfilter*</function> family of
functions, which generate LDAP filters that are based on an arbitrary search
string provided by a user.</para></entry>
</row>
<row>
<entry>
<para><filename>modattrs.c</filename></para></entry>
<entry>
<para>Shows how to use <function>ldap_modify_s</function> to replace and add
to values in an attribute.</para></entry>
</row>
<row>
<entry>
<para><filename>modrdn.c</filename></para></entry>
<entry>
<para>Shows how to use <function>ldap_modrdn2_s</function> to change the relative
distinguished name (RDN) of an entry.</para></entry>
</row>
<row>
<entry>
<para><filename>pwdextop.c</filename></para></entry>
<entry>
<para>Shows how to use the LDAP password modify extended operation to change
a password.</para></entry>
</row>
<row>
<entry>
<para><filename>pwdpolicy.c</filename></para></entry>
<entry>
<para>Shows how to use the password policy control. This control allows you
to retrieve information about the password policy that applies to the user
binding to the directory.</para></entry>
</row>
<row>
<entry>
<para><filename>rdentry.c</filename></para></entry>
<entry>
<para>Shows how to use <function>ldap_search_s</function> to retrieve a particular
entry from the directory.</para></entry>
</row>
<row>
<entry>
<para><filename>realattr.c</filename></para></entry>
<entry>
<para>Shows how to use the control to retrieve only real attributes during
a search.</para></entry>
</row>
<row>
<entry>
<para><filename>search.c</filename></para></entry>
<entry>
<para>Shows how to use <function>ldap_search_s</function> to search for all
entries that have an attribute value that exactly matches what you search
for. </para></entry>
</row>
<row>
<entry>
<para><filename>srvrsort.c</filename></para></entry>
<entry>
<para>Shows how to use server-side sorting in conjunction with the <function>ldap_search_ext_s
</function> function.</para></entry>
</row>
<row>
<entry>
<para><filename>ssearch.c</filename></para></entry>
<entry>
<para>Like <filename>ssnoauth.c</filename>, but includes certificate-based
authentication.</para></entry>
</row>
<row>
<entry>
<para><filename>ssnoauth.c</filename></para></entry>
<entry>
<para>Like <filename>search.c</filename>, but the search is done over an SSL-protected
TCP connection.</para></entry>
</row>
<row>
<entry>
<para><filename>starttls.c</filename></para></entry>
<entry>
<para>Shows how to use the Start TLS extended operation.</para></entry>
</row>
<row>
<entry>
<para><filename>userstatus.c</filename></para></entry>
<entry>
<para>Shows how to use the account status control to retrieve information
about the account of the user binding to the directory.</para></entry>
</row>
<row>
<entry>
<para><filename>virtattr.c</filename></para></entry>
<entry>
<para>Shows how to use the control to retrieve only virtual attributes during
a search.</para></entry>
</row>
<row>
<entry>
<para><filename>whoami.c</filename></para></entry>
<entry>
<para>Shows how to use the Who am I? extended operation to retrieve the authorization
ID.</para></entry>
</row>
</tbody>
</tgroup>
</table>
</sect2>
<sect2 id="bdabr"><title>Asynchronous Examples</title>
<indexterm>
<primary>C SDK</primary>
<secondary>asynchronous examples</secondary>
</indexterm><indexterm>
<primary>example programs</primary>
<secondary>C SDK</secondary>
<tertiary>asynchronous programs</tertiary>
</indexterm>
<para>These examples use the asynchronous LDAP calls. You begin an operation.
You then periodically poll to see if any results have been returned.</para>
<table frame="topbot" pgwide="1" id="csdk-async-examples"><title>Asynchronous
Example Programs</title>
<tgroup cols="2"><colspec colnum="1" colwidth="16.64*"><colspec colnum="2"
colwidth="83.36*">
<thead>
<row>
<entry>
<para>Example Source</para></entry>
<entry>
<para>Description</para></entry>
</row>
</thead>
<tbody>
<row>
<entry>
<para><filename>add.c</filename></para></entry>
<entry>
<para>Adds an entry to the directory.</para></entry>
</row>
<row>
<entry>
<para><filename>asearch.c</filename></para></entry>
<entry>
<para>Initiates a search for entries, printing the results on arrival.</para>
</entry>
</row>
<row>
<entry>
<para><filename>del.c</filename></para></entry>
<entry>
<para>Deletes an entry from the directory.</para></entry>
</row>
<row>
<entry>
<para><filename>nsprio.c</filename></para></entry>
<entry>
<para>Like <literal>asearch.</literal> but uses the PerLDAP routines to incorporate
the Netscape Portable Runtime (NSPR) API.</para></entry>
</row>
<row>
<entry>
<para><filename>ppolicy.c</filename></para></entry>
<entry>
<para>Attempts to bind to the directory and reports back any password expiration
information received. This program demonstrates how clients can process password
policy information.</para></entry>
</row>
<row>
<entry>
<para><filename>psearch.c</filename></para></entry>
<entry>
<para>Shows how to use Persistent Search, an LDAP v3 extension, to monitor
a directory for changes.</para></entry>
</row>
</tbody>
</tgroup>
</table>
</sect2>
</sect1>
</chapter>

View File

@@ -0,0 +1,178 @@
<!--
Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
Portions copyright 1999 Netscape Communications Corporation. All
Rights Reserved.
The contents of this document are subject to the terms of the
Creative Commons Attribution-ShareAlike 2.5 license or any later
version (the "License"). You may not use this document except in
compliance with the License.
See the License for the specific language governing
permissions and limitations under the License. You can obtain
a copy of the License at
http://creativecommons.org/licenses/by-sa/2.5/legalcode.
-->
<chapter id="csdk-whatsnew"><title>What's New In &DirectorySDKForC;</title>
<indexterm>
<primary>upgrading</primary>
<secondary>C SDK</secondary>
</indexterm><highlights>
<para>This chapter compares the current version of &DirectorySDKForC; API
with the previous version.</para>
<itemizedlist>
<para>This chapter covers the following topics:</para>
<listitem><para><olink targetptr="csdk-changed-features">Deprecated and Changed
Directory SDK for C Features</olink></para></listitem>
<listitem><para><olink targetptr="csdk-new-features">New Directory SDK for
C Features</olink></para></listitem>
</itemizedlist>
</highlights><?Pub Caret1>
<sect1 id="csdk-changed-features"><title>Deprecated and Changed &DirectorySDKForC; Features
</title>
<indexterm>
<primary>deprecated features</primary>
<secondary>C SDK</secondary>
</indexterm>
<para>This section covers the following changes and deprecated features in
this release. Where possible, &DirectorySDKForC; provides replacement features
for deprecated features.</para>
<itemizedlist>
<listitem><para><literal>liblber</literal> API</para></listitem>
<listitem><para>File layout</para></listitem>
<listitem><para>IPv6 support</para></listitem>
<listitem><para>NSS and NSPR version updates</para></listitem>
<listitem><para>NSS security tools</para></listitem>
</itemizedlist>
<sect2 id="liblber-changes"><title><filename class="libraryfile">liblber</filename> API
</title>
<indexterm>
<primary>APIs</primary>
<secondary><filename class="libraryfile">liblber</filename></secondary>
</indexterm><indexterm>
<primary>libraries</primary>
<secondary><filename class="libraryfile">liblber</filename></secondary>
</indexterm>
<para>The Basic Encoding Rules library, <filename class="libraryfile">liblber</filename>,
changed for portability reasons and to comply with <citetitle>The C LDAP Application
Program Interface</citetitle> Internet draft. In particular, according to
section 17.1., <citetitle>BER Data Structures and Types,</citetitle> the following
structures have changed.</para>
<programlisting role="fragment">The following additional integral types are defined for use in manipula-
tion of BER encoded ASN.1 values:
typedef &lt;impl_tag_t> ber_tag_t; /* for BER tags */
typedef &lt;impl_int_t> ber_int_t; /* for BER ints, enums, and Booleans */
typedef &lt;impl_unit_t> ber_uint_t; /* unsigned equivalent of ber_uint_t */
typedef &lt;impl_slen_t> ber_slen_t; /* signed equivalent of ber_len_t */
Note that the actual definition for these four integral types is imple-
mentation specific; that is, `&lt;impl_tag_t>', `&lt;impl_int_t>',
`&lt;impl_uint_t>', and `&lt;impl_slen_t>' MUST each be replaced with an
appropriate implementation-specific type.</programlisting>
<para>Programs that do not use the <filename class="libraryfile">liblber</filename> API
directly need not be changed. You can continue to build and use those applications
as before.</para>
<para>If, however, your programs call the <filename class="libraryfile">liblber</filename> API
directly, you must change your application code to reflect the type definitions
in <filename>include/lber.h</filename>. Compilers typically issue type mismatch
warnings when compiling old code that has not been fixed.</para></sect2>
<sect2 id="csdk-file-layout-changes"><title>File Layout</title>
<para>The file layout has changed. All files are unpacked in a base directory
that is named according to the platform and to the operating system of the
binary distribution. The file layout is covered in the section on <olink targetptr="bdaaw">Files Provided With Directory SDK for C</olink>.</para>
</sect2>
<sect2 id="csdk-ipv6-support"><title>IPv6 Support</title>
<para>IPv6 support is provided by means of the NSPR library. Therefore, to
use LDAP over IPv6, use <function>prldap_init</function> instead of <function>ldap_init
</function>.</para></sect2>
<sect2 id="csdk-nss-nspr-versions"><title>NSS and NSPR Version Updates</title>
<para>This version of &DirectorySDKForC; uses NSS 3.11and NSPR 4.6. Both
components are included in binary form for your convenience.</para></sect2>
<sect2 id="nss-security-tools"><title>NSS Security Tools</title>
<para>NSS security tools, used to maintain NSS databases so your application
can do LDAP over SSL, are not delivered with &DirectorySDKForC;.</para>
<para>For access to NSS security tools, refer to the <ulink
url="http://www.mozilla.org/projects/security/pki/nss/tools/" type="text_url">NSS
security tools project</ulink>.</para></sect2>
</sect1>
<sect1 id="csdk-new-features"><title>New &DirectorySDKForC; Features</title>
<indexterm>
<primary>new features</primary>
<secondary>C SDK</secondary>
</indexterm><indexterm>
<primary>C SDK</primary>
<secondary>new features of</secondary>
</indexterm>
<itemizedlist remap="jumplist">
<para>This section describes the features introduced in this release:</para>
<listitem><para><olink targetptr="csdk-ldap-v3-default">LDAP Version 3 Default</olink></para>
</listitem>
<listitem><para><olink targetptr="csdk-more-supported-controls">Supported
Controls</olink></para></listitem>
<listitem><para><olink targetptr="csdk-more-extop-support">Supported Extended
Operations</olink></para></listitem>
<listitem><para><olink targetptr="csdk-more-sample-code">Additional Directory
SDK for C Examples</olink></para></listitem>
</itemizedlist>
<sect2 id="csdk-ldap-v3-default"><title>LDAP Version 3 Default</title>
<para>&DirectorySDKForC; now uses LDAP v3 by default. You can therefore
use LDAP v3 features in your applications even if you do not specifically
set the version to 3.</para></sect2>
<sect2 id="csdk-more-supported-controls"><title>Supported Controls</title>
<para>This version of &DirectorySDKForC; adds support for developing client
applications, including more than 10 LDAP v3 controls. See <olink targetptr="controls-oids">Table 16&ndash;1</olink> for a complete list.</para>
<para>For instructions on using controls supported by &DirectorySDKForC;,
see <olink targetptr="csdk-controls">Chapter&nbsp;16, LDAP Controls With Directory
SDK for C</olink>.</para></sect2>
<sect2 id="csdk-more-extop-support"><title>Supported Extended Operations</title>
<indexterm>
<primary>extended operations</primary>
<secondary>C SDK support of</secondary>
</indexterm>
<para>This version of &DirectorySDKForC; adds support for developing client
applications that use the following extended operations.</para>
<variablelist>
<varlistentry><term>LDAP Password Modify Extended Operation</term>
<listitem><para>The LDAP Password Modify extended operation lets your client
application modify a user password through LDAP. A user can modify his password
even if the password is not stored as an attribute in the directory, the user
is not identified by a DN, or the user does not have an entry in the directory.
The LDAP Password Modify extended operation is defined in <ulink
url="http://www.ietf.org/rfc/rfc3062.txt" type="text_url">RFC 3062</ulink>.</para>
<para>The extended operation has identifier <literal>1.3.6.1.4.1.4203.1.11.1</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry><term>Start TLS Extended Operation</term>
<listitem><para>The Start TLS extended operation lets your client application
connect to a nonsecure port, and then request transport layer security.</para>
<para>The extended operation has identifier <literal>1.3.6.1.4.1.1466.20037</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry><term>Who Am I? Extended Operation</term>
<listitem><para>The &ldquo;Who am I?&rdquo; extended operation lets your client
application determine the authorization identity that the server currently
associates with your client.</para>
<para>The extended operation has identifier <literal>1.3.6.1.4.1.4203.1.11.3</literal>.
</para>
</listitem>
</varlistentry>
</variablelist>
<para>For instructions on using extended operations supported by &DirectorySDKForC;,
see <olink targetptr="csdk-extop">Chapter&nbsp;18, Extended Operations With
Directory SDK for C</olink>.</para></sect2>
<sect2 id="csdk-more-sample-code"><title>Additional &DirectorySDKForC; Examples
</title>
<indexterm>
<primary>example programs</primary>
<secondary>C SDK</secondary>
</indexterm>
<para>More sample code is provided in the <filename>examples/</filename> directory.
The additional samples demonstrate newly supported controls and extended operations.
</para></sect2>
</sect1>
</chapter>

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@@ -0,0 +1,113 @@
<!--
Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
Portions copyright 1999 Netscape Communications Corporation. All
Rights Reserved.
The contents of this document are subject to the terms of the
Creative Commons Attribution-ShareAlike 2.5 license or any later
version (the "License"). You may not use this document except in
compliance with the License.
See the License for the specific language governing
permissions and limitations under the License. You can obtain
a copy of the License at
http://creativecommons.org/licenses/by-sa/2.5/legalcode.
-->
<para>Copyright 2000-2007 Sun Microsystems, Inc., 4150 Network Circle,
Santa Clara, California 95054, U.S.A. All rights reserved. Portions
copyright 1999 Netscape Communications Corporations. All rights
reserved.</para>
<para>Sun Microsystems, Inc. has intellectual property rights relating
to technology embodied in the product that is described in this
document. In particular, and without limitation, these intellectual
property rights may include one or more U.S. patents or pending patent
applications in the U.S. and in other countries.</para>
<para>U.S. Government Rights - Commercial software. Government users
are subject to the Sun Microsystems, Inc. standard license agreement
and applicable provisions of the FAR and its supplements.</para>
<para>This distribution may include materials developed by third
parties.</para>
<para>Parts of the product may be derived from Berkeley BSD systems,
licensed from the University of California. UNIX is a registered
trademark in the U.S. and in other countries, exclusively licensed
through X/Open Company, Ltd.</para>
<para>Sun, Sun Microsystems, the Sun logo, Java, Solaris, JavaBeans,
JavaScript and the SunTone Certified logo are trademarks or registered
trademarks of Sun Microsystems, Inc. in the U.S. and other
countries.</para>
<para>All SPARC trademarks are used under license and are trademarks
or registered trademarks of SPARC International, Inc. in the U.S. and
other countries. Products bearing SPARC trademarks are based upon
architecture developed by Sun Microsystems, Inc.</para>
<para>Mozilla, Netscape, and Netscape Navigator are trademarks or
registered trademarks of Netscape Communications Corporation in the
United States and other countries.</para>
<para>Products covered by and information contained in this service
manual are controlled by U.S. Export Control laws and may be subject
to the export or import laws in other countries. Nuclear, missile,
chemical biological weapons or nuclear maritime end uses or end users,
whether direct or indirect, are strictly prohibited. Export or
reexport to countries subject to U.S. embargo or to entities
identified on U.S. export exclusion lists, including, but not limited
to, the denied persons and specially designated nationals lists is
strictly prohibited.</para>
<para>DOCUMENTATION IS PROVIDED &ldquo;AS IS&rdquo; AND ALL EXPRESS OR
IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
OR NON-INFRINGEMENT, ARE DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH
DISCLAIMERS ARE HELD TO BE LEGALLY INVALID.</para>
<para>Copyright 2000-2007 Sun Microsystems, Inc., 4150 Network Circle,
Santa Clara, California 95054, Etats-Unis. Tous droits
r&eacute;serv&eacute;s. Certaines parties copyright 1999 Netscape
Communications Corporations. Tous droits r&eacute;serv&eacute;s.</para>
<para>Sun Microsystems, Inc. d&eacute;tient les droits de
propri&eacute;t&eacute; intellectuelle relatifs &agrave; la
technologie incorpor&eacute;e dans le produit qui est d&eacute;crit
dans ce document. En particulier, et ce sans limitation, ces droits de
propri&eacute;t&eacute; intellectuelle peuvent inclure un ou plusieurs
brevets am&eacute;ricains ou des applications de brevet en attente aux
Etats-Unis et dans d'autres pays.</para>
<para>Cette distribution peut comprendre des composants
d&eacute;velopp&eacute;s par des tierces parties.</para>
<para>Des parties de ce produit pourront &ecirc;tre
d&eacute;riv&eacute;es des syst&egrave;mes Berkeley BSD
licenci&eacute;s par l'Universit&eacute; de Californie. UNIX est une
marque d&eacute;pos&eacute;e aux Etats-Unis et dans d'autres pays et
licenci&eacute;e exclusivement par X/Open Company, Ltd.</para>
<para>Sun, Sun Microsystems, le logo Sun, Java, Solaris, JavaBeans,
JavaScript et le logo SunTone Certified sont des marques de fabrique
ou des marques d&eacute;pos&eacute;es de Sun Microsystems, Inc. aux
Etats-Unis et dans d'autres pays.</para>
<para>Toutes les marques SPARC sont utilis&eacute;es sous licence et
sont des marques de fabrique ou des marques d&eacute;pos&eacute;es de
SPARC International, Inc. aux Etats-Unis et dans d'autres pays. Les
produits portant les marques SPARC sont bas&eacute;s sur une
architecture d&eacute;velopp&eacute;e par Sun Microsystems,
Inc.</para>
<para>Mozilla, Netscape, et Netscape Navigator sont des marques de
Netscape Communications Corporation aux Etats-Unis et dans d'autres
pays.</para>
<para>Les produits qui font l'objet de ce manuel d'entretien et les
informations qu'il contient sont regis par la legislation americaine
en matiere de controle des exportations et peuvent etre soumis au
droit d'autres pays dans le domaine des exportations et
importations. Les utilisations finales, ou utilisateurs finaux, pour
des armes nucleaires, des missiles, des armes biologiques et chimiques
ou du nucleaire maritime, directement ou indirectement, sont
strictement interdites. Les exportations ou reexportations vers des
pays sous embargo des Etats-Unis, ou vers des entites figurant sur les
listes d'exclusion d'exportation americaines, y compris, mais de
maniere non exclusive, la liste de personnes qui font objet d'un ordre
de ne pas participer, d'une facon directe ou indirecte, aux
exportations des produits ou des services qui sont regi par la
legislation americaine en matiere de controle des exportations et la
liste de ressortissants specifiquement designes, sont rigoureusement
interdites.</para>
<para>LA DOCUMENTATION EST FOURNIE &ldquo;EN L'ETAT&rdquo; ET TOUTES
AUTRES CONDITIONS, DECLARATIONS ET GARANTIES EXPRESSES OU TACITES SONT
FORMELLEMENT EXCLUES, DANS LA MESURE AUTORISEE PAR LA LOI APPLICABLE,
Y COMPRIS NOTAMMENT TOUTE GARANTIE IMPLICITE RELATIVE A LA QUALITE
MARCHANDE, A L'APTITUDE A UNE UTILISATION PARTICULIERE OU A L'ABSENCE
DE CONTREFACON. </para>

View File

@@ -0,0 +1,226 @@
Attribution-ShareAlike 2.5
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL
SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN ATTORNEY-CLIENT
RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS.
CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE INFORMATION PROVIDED, AND
DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM ITS USE.
License
THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS
PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR
OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS
LICENSE OR COPYRIGHT LAW IS PROHIBITED.
BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE
BOUND BY THE TERMS OF THIS LICENSE. THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED
HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS.
1. Definitions
1. "Collective Work" means a work, such as a periodical issue, anthology or
encyclopedia, in which the Work in its entirety in unmodified form, along with a
number of other contributions, constituting separate and independent works in
themselves, are assembled into a collective whole. A work that constitutes a
Collective Work will not be considered a Derivative Work (as defined below) for
the purposes of this License.
2. "Derivative Work" means a work based upon the Work or upon the Work and
other pre-existing works, such as a translation, musical arrangement,
dramatization, fictionalization, motion picture version, sound recording, art
reproduction, abridgment, condensation, or any other form in which the Work may
be recast, transformed, or adapted, except that a work that constitutes a
Collective Work will not be considered a Derivative Work for the purpose of this
License. For the avoidance of doubt, where the Work is a musical composition or
sound recording, the synchronization of the Work in timed-relation with a moving
image ("synching") will be considered a Derivative Work for the purpose of this
License.
3. "Licensor" means the individual or entity that offers the Work under the
terms of this License.
4. "Original Author" means the individual or entity who created the Work.
5. "Work" means the copyrightable work of authorship offered under the terms
of this License.
6. "You" means an individual or entity exercising rights under this License
who has not previously violated the terms of this License with respect to the
Work, or who has received express permission from the Licensor to exercise
rights under this License despite a previous violation.
7. "License Elements" means the following high-level license attributes as
selected by Licensor and indicated in the title of this License: Attribution,
ShareAlike.
2. Fair Use Rights. Nothing in this license is intended to reduce, limit, or
restrict any rights arising from fair use, first sale or other limitations on
the exclusive rights of the copyright owner under copyright law or other
applicable laws.
3. License Grant. Subject to the terms and conditions of this License, Licensor
hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the
duration of the applicable copyright) license to exercise the rights in the Work
as stated below:
1. to reproduce the Work, to incorporate the Work into one or more Collective
Works, and to reproduce the Work as incorporated in the Collective Works;
2. to create and reproduce Derivative Works;
3. to distribute copies or phonorecords of, display publicly, perform
publicly, and perform publicly by means of a digital audio transmission the Work
including as incorporated in Collective Works;
4. to distribute copies or phonorecords of, display publicly, perform
publicly, and perform publicly by means of a digital audio transmission
Derivative Works.
5.
For the avoidance of doubt, where the work is a musical composition:
1. Performance Royalties Under Blanket Licenses. Licensor waives the
exclusive right to collect, whether individually or via a performance rights
society (e.g. ASCAP, BMI, SESAC), royalties for the public performance or public
digital performance (e.g. webcast) of the Work.
2. Mechanical Rights and Statutory Royalties. Licensor waives the
exclusive right to collect, whether individually or via a music rights society
or designated agent (e.g. Harry Fox Agency), royalties for any phonorecord You
create from the Work ("cover version") and distribute, subject to the compulsory
license created by 17 USC Section 115 of the US Copyright Act (or the equivalent
in other jurisdictions).
6. Webcasting Rights and Statutory Royalties. For the avoidance of doubt,
where the Work is a sound recording, Licensor waives the exclusive right to
collect, whether individually or via a performance-rights society (e.g.
SoundExchange), royalties for the public digital performance (e.g. webcast) of
the Work, subject to the compulsory license created by 17 USC Section 114 of the
US Copyright Act (or the equivalent in other jurisdictions).
The above rights may be exercised in all media and formats whether now known or
hereafter devised. The above rights include the right to make such modifications
as are technically necessary to exercise the rights in other media and formats.
All rights not expressly granted by Licensor are hereby reserved.
4. Restrictions.The license granted in Section 3 above is expressly made subject
to and limited by the following restrictions:
1. You may distribute, publicly display, publicly perform, or publicly
digitally perform the Work only under the terms of this License, and You must
include a copy of, or the Uniform Resource Identifier for, this License with
every copy or phonorecord of the Work You distribute, publicly display, publicly
perform, or publicly digitally perform. You may not offer or impose any terms on
the Work that alter or restrict the terms of this License or the recipients'
exercise of the rights granted hereunder. You may not sublicense the Work. You
must keep intact all notices that refer to this License and to the disclaimer of
warranties. You may not distribute, publicly display, publicly perform, or
publicly digitally perform the Work with any technological measures that control
access or use of the Work in a manner inconsistent with the terms of this
License Agreement. The above applies to the Work as incorporated in a Collective
Work, but this does not require the Collective Work apart from the Work itself
to be made subject to the terms of this License. If You create a Collective
Work, upon notice from any Licensor You must, to the extent practicable, remove
from the Collective Work any credit as required by clause 4(c), as requested. If
You create a Derivative Work, upon notice from any Licensor You must, to the
extent practicable, remove from the Derivative Work any credit as required by
clause 4(c), as requested.
2. You may distribute, publicly display, publicly perform, or publicly
digitally perform a Derivative Work only under the terms of this License, a
later version of this License with the same License Elements as this License, or
a Creative Commons iCommons license that contains the same License Elements as
this License (e.g. Attribution-ShareAlike 2.5 Japan). You must include a copy
of, or the Uniform Resource Identifier for, this License or other license
specified in the previous sentence with every copy or phonorecord of each
Derivative Work You distribute, publicly display, publicly perform, or publicly
digitally perform. You may not offer or impose any terms on the Derivative Works
that alter or restrict the terms of this License or the recipients' exercise of
the rights granted hereunder, and You must keep intact all notices that refer to
this License and to the disclaimer of warranties. You may not distribute,
publicly display, publicly perform, or publicly digitally perform the Derivative
Work with any technological measures that control access or use of the Work in a
manner inconsistent with the terms of this License Agreement. The above applies
to the Derivative Work as incorporated in a Collective Work, but this does not
require the Collective Work apart from the Derivative Work itself to be made
subject to the terms of this License.
3. If you distribute, publicly display, publicly perform, or publicly
digitally perform the Work or any Derivative Works or Collective Works, You must
keep intact all copyright notices for the Work and provide, reasonable to the
medium or means You are utilizing: (i) the name of the Original Author (or
pseudonym, if applicable) if supplied, and/or (ii) if the Original Author and/or
Licensor designate another party or parties (e.g. a sponsor institute,
publishing entity, journal) for attribution in Licensor's copyright notice,
terms of service or by other reasonable means, the name of such party or
parties; the title of the Work if supplied; to the extent reasonably
practicable, the Uniform Resource Identifier, if any, that Licensor specifies to
be associated with the Work, unless such URI does not refer to the copyright
notice or licensing information for the Work; and in the case of a Derivative
Work, a credit identifying the use of the Work in the Derivative Work (e.g.,
"French translation of the Work by Original Author," or "Screenplay based on
original Work by Original Author"). Such credit may be implemented in any
reasonable manner; provided, however, that in the case of a Derivative Work or
Collective Work, at a minimum such credit will appear where any other comparable
authorship credit appears and in a manner at least as prominent as such other
comparable authorship credit.
5. Representations, Warranties and Disclaimer
UNLESS OTHERWISE AGREED TO BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK
AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE
MATERIALS, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT
LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR
PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY,
OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME
JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH
EXCLUSION MAY NOT APPLY TO YOU.
6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN
NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL,
INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS
LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
7. Termination
1. This License and the rights granted hereunder will terminate automatically
upon any breach by You of the terms of this License. Individuals or entities who
have received Derivative Works or Collective Works from You under this License,
however, will not have their licenses terminated provided such individuals or
entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7,
and 8 will survive any termination of this License.
2. Subject to the above terms and conditions, the license granted here is
perpetual (for the duration of the applicable copyright in the Work).
Notwithstanding the above, Licensor reserves the right to release the Work under
different license terms or to stop distributing the Work at any time; provided,
however that any such election will not serve to withdraw this License (or any
other license that has been, or is required to be, granted under the terms of
this License), and this License will continue in full force and effect unless
terminated as stated above.
8. Miscellaneous
1. Each time You distribute or publicly digitally perform the Work or a
Collective Work, the Licensor offers to the recipient a license to the Work on
the same terms and conditions as the license granted to You under this License.
2. Each time You distribute or publicly digitally perform a Derivative Work,
Licensor offers to the recipient a license to the original Work on the same
terms and conditions as the license granted to You under this License.
3. If any provision of this License is invalid or unenforceable under
applicable law, it shall not affect the validity or enforceability of the
remainder of the terms of this License, and without further action by the
parties to this agreement, such provision shall be reformed to the minimum
extent necessary to make such provision valid and enforceable.
4. No term or provision of this License shall be deemed waived and no breach
consented to unless such waiver or consent shall be in writing and signed by the
party to be charged with such waiver or consent.
5. This License constitutes the entire agreement between the parties with
respect to the Work licensed here. There are no understandings, agreements or
representations with respect to the Work not specified here. Licensor shall not
be bound by any additional provisions that may appear in any communication from
You. This License may not be modified without the mutual written agreement of
the Licensor and You.
Creative Commons is not a party to this License, and makes no warranty
whatsoever in connection with the Work. Creative Commons will not be liable to
You or any party on any legal theory for any damages whatsoever, including
without limitation any general, special, incidental or consequential damages
arising in connection to this license. Notwithstanding the foregoing two (2)
sentences, if Creative Commons has expressly identified itself as the Licensor
hereunder, it shall have all rights and obligations of Licensor.
Except for the limited purpose of indicating to the public that the Work is
licensed under the CCPL, neither party will use the trademark "Creative Commons"
or any related trademark or logo of Creative Commons without the prior written
consent of Creative Commons. Any permitted use will be in compliance with
Creative Commons' then-current trademark usage guidelines, as may be published
on its website or otherwise made available upon request from time to time.
Creative Commons may be contacted at http://creativecommons.org/.

View File

@@ -0,0 +1,375 @@
<!--
Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
Portions copyright 1999 Netscape Communications Corporation. All
Rights Reserved.
The contents of this document are subject to the terms of the
Creative Commons Attribution-ShareAlike 2.5 license or any later
version (the "License"). You may not use this document except in
compliance with the License.
See the License for the specific language governing
permissions and limitations under the License. You can obtain
a copy of the License at
http://creativecommons.org/licenses/by-sa/2.5/legalcode.
-->
<preface id="preface"><title>Preface</title>
<highlights>&abstract;
</highlights>
<sect1 id="who-should-read"><title>Who Should Use This Book</title>
<para>This guide is intended for developers creating directory client applications.
</para>
<itemizedlist>
<para>Before using this guide, you must be familiar with the following:</para>
<listitem><para>&cnDirectoryServer; functionality</para></listitem>
<listitem><para>Developing programs in the C programming
language</para></listitem>
<listitem><para>Specifications for LDAP and related protocols, such as DSML
v2</para></listitem>
<listitem><para>Internet and World Wide Web technologies</para></listitem>
</itemizedlist>
</sect1>
<sect1 id="before-you-read"><title>Before You Read This Book</title>
<para>Before developing directory client applications, install &DirectorySDKForJava;.
</para>
<!-- TODO: Need an XREF to installation instructions -->
</sect1>
<sect1 id="reading-for-developers"><title>Additional Recommended Reading</title>
<itemizedlist>
<para>Directory client application developers might benefit from reading the
following books:</para>
<listitem><para><citetitle>LDAP Programming with Java</citetitle> by Weltman
and Dabhura (ISBN 0-201-65758-96)</para></listitem>
<listitem><para><citetitle>LDAP Programming, Management and Integration</citetitle> by
Donley (ISBN 1930110405)</para></listitem>
<listitem><para><citetitle>LDAP: Programming Directory-Enabled Applications
with Lightweight Directory Access Protocol</citetitle> by Howes and Smith
(ISBN 1-57870-000-00)</para></listitem>
<listitem><para><citetitle>Understanding and Deploying LDAP Directory Services</citetitle> by
Howes, et al. (ISBN 1-57870-070-10)</para></listitem>
</itemizedlist>
<itemizedlist>
<para>In addition, keep bookmarks to the following IETF documents:</para>
<listitem><para><ulink url="http://www.ietf.org/rfc/rfc2251.txt" type="text_url">
RFC 2251</ulink>, <citetitle>Lightweight Directory Access Protocol (v3)</citetitle></para>
</listitem>
<listitem><para><ulink url="http://www.ietf.org/rfc/rfc2252.txt" type="text_url">
RFC 2252</ulink>, <citetitle>Lightweight Directory Access Protocol (v3): Attribute
Syntax Definitions</citetitle></para></listitem>
<listitem><para><ulink url="http://www.ietf.org/rfc/rfc2253.txt" type="text_url">
RFC 2253</ulink>, <citetitle>Lightweight Directory Access Protocol (v3): UTF-8
String Representation of Distinguished Names</citetitle></para></listitem>
<listitem><para><ulink url="http://www.ietf.org/rfc/rfc2254.txt" type="text_url">
RFC 2254</ulink>, <citetitle>The String Representation of LDAP Search Filters</citetitle></para>
</listitem>
<listitem><para><ulink url="http://www.ietf.org/rfc/rfc2255.txt" type="text_url">
RFC 2255</ulink>, <citetitle>The LDAP URL Format</citetitle></para></listitem>
<listitem><para><ulink url="http://www.ietf.org/rfc/rfc2256.txt" type="text_url">
RFC 2256</ulink>, <citetitle>A Summary of the X.500(96) User Schema for use
with LDAPv3</citetitle></para></listitem>
<listitem><para><ulink url="http://www.ietf.org/rfc/rfc2829.txt" type="text_url">
RFC 2829</ulink>, <citetitle>Authentication Methods for LDAP</citetitle></para>
</listitem>
<listitem><para><ulink url="http://www.ietf.org/rfc/rfc2830.txt" type="text_url">
RFC 2830</ulink>, <citetitle>Lightweight Directory Access Protocol (v3): Extension
for Transport Layer Security</citetitle></para></listitem>
<listitem><para><ulink url="http://www.ietf.org/rfc/rfc2849.txt" type="text_url">
RFC 2849</ulink>, <citetitle>The LDAP Data Interchange Format (LDIF) - Technical
Specification</citetitle></para></listitem>
<listitem><para><ulink url="http://www.ietf.org/rfc/rfc3377.txt" type="text_url">
RFC 3377</ulink>, <citetitle>Lightweight Directory Access Protocol (v3): Technical
Specification</citetitle></para></listitem>
</itemizedlist>
</sect1>
<sect1 id="organization"><title>How This Book Is Organized</title>
<itemizedlist>
<para>This guide includes the following chapters.</para>
<listitem><para><olink targetptr="understanding-ldap">Chapter&nbsp;1, Understanding
LDAP</olink> describes LDAP and directory concepts.</para></listitem>
<listitem><para><olink targetptr="best-practices-choose">Chapter&nbsp;2, Choosing
a Client SDK</olink> covers what to consider when choosing a software development
kit for building directory client applications.</para></listitem>
<listitem><para><olink targetptr="best-practices-overview">Chapter&nbsp;3,
Best Practices for Writing Client Applications</olink> reviews what and what
not to do when building directory client applications.</para></listitem>
<listitem><para><olink targetptr="csdk-using">Chapter&nbsp;4, About Directory
SDK for C</olink> describes what &DirectorySDKForC; offers you as a directory
client developer.</para></listitem>
<listitem><para><olink targetptr="csdk-quickstart">Chapter&nbsp;5, Getting
Started With Directory SDK for C</olink> gets you started using &DirectorySDKForC;.
</para></listitem>
<listitem><para><olink targetptr="csdk-whatsnew">Chapter&nbsp;6, What's New
In Directory SDK for C</olink> presents new features, and changes from previous
versions of &DirectorySDKForC;.</para></listitem>
<listitem><para><olink targetptr="csdk-client">Chapter&nbsp;7, Writing an
LDAP Client With Directory SDK for C</olink> covers the basics of writing
a directory client application.</para></listitem>
<listitem><para><olink targetptr="csdk-api">Chapter&nbsp;8, Using the LDAP
C API</olink> shows how to write an application with &DirectorySDKForC;.</para>
</listitem>
<listitem><para><olink targetptr="csdk-searching">Chapter&nbsp;9, Searching
the Directory With Directory SDK for C</olink> shows how to write client application
code for searching a directory.</para></listitem>
<listitem><para><olink targetptr="csdk-filter">Chapter&nbsp;10, Using Filter
Configuration Files With Directory SDK for C</olink> shows how to write code
to search a directory using filter configuration files.</para></listitem>
<listitem><para><olink targetptr="csdk-write">Chapter&nbsp;11, Adding, Updating,
and Deleting Entries With Directory SDK for C</olink> shows how to write client
application code for changing directory entries.</para></listitem>
<listitem><para><olink targetptr="csdk-compare">Chapter&nbsp;12, Comparing
Attribute Values With Directory SDK for C</olink> shows how to compare attribute
values in a directory with known values.</para></listitem>
<listitem><para><olink targetptr="csdk-urls">Chapter&nbsp;13, LDAP URLs With
Directory SDK for C</olink> shows how to handle LDAP URLs.</para></listitem>
<listitem><para><olink targetptr="csdk-server-info">Chapter&nbsp;14, Getting
Server Information With Directory SDK for C</olink> shows how to retrieve
information about the directory and directory service.</para></listitem>
<listitem><para><olink targetptr="csdk-ssl">Chapter&nbsp;15, SSL Connections
With Directory SDK for C</olink> shows how to write client application code
that connects to the directory over SSL.</para></listitem>
<listitem><para><olink targetptr="csdk-controls">Chapter&nbsp;16, LDAP Controls
With Directory SDK for C</olink> shows how to handle supported LDAP controls.</para>
</listitem>
<listitem><para><olink targetptr="csdk-sasl">Chapter&nbsp;17, SASL Authentication
With Directory SDK for C</olink> shows how to connect to the directory by
using SASL.</para></listitem>
<listitem><para><olink targetptr="csdk-extop">Chapter&nbsp;18, Extended Operations
With Directory SDK for C</olink> shows how to write client application code
for handling LDAP v3 extended operations.</para></listitem>
<listitem><para><olink targetptr="csdk-multithread">Chapter&nbsp;19, Writing
Multithreaded Clients With Directory SDK for C</olink> shows how to write
multithreaded client application code.</para></listitem>
<listitem><para><olink targetptr="bdajr">Chapter&nbsp;20, Directory SDK for C Data Type Reference</olink> covers &DirectorySDKForC; data types</para>
</listitem>
<listitem><para><olink targetptr="bdane">Chapter&nbsp;21, Directory SDK for C Function Reference</olink> covers &DirectorySDKForC; functions</para>
</listitem>
<listitem><para><olink targetptr="bdaxx">Chapter&nbsp;22, Directory SDK for C Result Codes</olink> covers &DirectorySDKForC; function result codes</para>
</listitem>
<listitem><para><olink targetptr="share-alike">Appendix A, Creative Commons Attribution-ShareAlike 2.5</olink> provides the full text of the license governing this guide</para>
</listitem>
</itemizedlist>
</sect1>
<sect1 id="related-reading"><title>Related Reading</title>
<para><indexterm>
<primary>SLAMD Distributed Load Generation Engine</primary>
</indexterm>The SLAMD Distributed Load Generation Engine (SLAMD) is a <trademark>
Java</trademark> application that is designed to stress test and analyze the
performance of network-based applications. It was originally developed by
Sun Microsystems, Inc. to benchmark and analyze the performance of LDAP directory
servers. SLAMD is available as an open source application under the Sun Public
License, an OSI-approved open source license. To obtain information about
SLAMD, go to <ulink url="http://www.slamd.com/" type="url"></ulink>. SLAMD
is also available as a java.net project. See <ulink
url="https://slamd.dev.java.net/" type="url"></ulink>.</para>
<para><indexterm>
<primary>Java Naming and Directory Interface</primary>
</indexterm>Java Naming and Directory Interface (JNDI) technology supports
accessing the Directory Server using LDAP and DSML v2 from Java applications.
For information about JNDI, see <ulink url="http://java.sun.com/products/jndi/"
type="url"></ulink>. The <citetitle>JNDI Tutorial</citetitle> contains detailed
descriptions and examples of how to use JNDI. This tutorial is at <ulink
url="http://java.sun.com/products/jndi/tutorial/" type="url"></ulink>.</para>
</sect1>
<sect1 id="FWBKX"><title>Typographic Conventions</title>
<para>The following table describes the typographic changes that are used
in this book.</para>
<table frame="topbot" id="FWBTE"><title>Typographic Conventions</title>
<tgroup cols="3" colsep="0" rowsep="0"><colspec colwidth="15*"><colspec
colwidth="40*"><colspec colwidth="45*">
<thead>
<row rowsep="1">
<entry align="left">
<para>Typeface</para></entry>
<entry align="left">
<para>Meaning</para></entry>
<entry align="left">
<para>Example</para></entry>
</row>
</thead>
<tbody>
<row>
<entry>
<para><literal>AaBbCc123</literal></para></entry>
<entry>
<para>The names of commands, files, and directories, and onscreen computer
output</para></entry>
<entry>
<para>Edit your <filename>.login</filename> file.</para>
<para>Use <command>ls <option>a</option></command> to list all files.</para>
<para><computeroutput>machine_name% you have mail.</computeroutput></para>
</entry>
</row>
<row>
<entry>
<para><userinput>AaBbCc123</userinput></para></entry>
<entry>
<para>What you type, contrasted with onscreen computer output</para></entry>
<entry>
<para><computeroutput>machine_name%</computeroutput> <userinput>su</userinput></para>
<para><computeroutput>Password:</computeroutput></para></entry>
</row>
<row>
<entry>
<para><replaceable>AaBbCc123</replaceable></para></entry>
<entry>
<para>A placeholder to be replaced with a real name or value</para></entry>
<entry>
<para>The command to remove a file is <command>rm</command> <replaceable>filename
</replaceable>.</para></entry>
</row>
<row>
<entry>
<para><emphasis>AaBbCc123</emphasis></para></entry>
<entry>
<para>Book titles, new terms, and terms to be emphasized (note that some emphasized
items appear bold online)</para></entry>
<entry>
<para>Read Chapter 6 in the <citetitle>User's Guide</citetitle>.</para>
<para>A <emphasis>cache</emphasis> is a copy that is stored locally.</para>
<para>Do <emphasis>not</emphasis> save the file.</para></entry>
</row>
</tbody>
</tgroup>
</table>
</sect1>
<sect1 id="FWBMK"><title>Shell Prompts in Command Examples</title>
<para>The following table shows default system prompts and superuser prompts.</para>
<table frame="topbot" id="GCTTT"><title>Shell Prompts</title>
<tgroup cols="2" colsep="0" rowsep="0"><colspec colwidth="75*"><colspec
colwidth="25*">
<thead>
<row rowsep="1">
<entry>
<para>Shell</para></entry>
<entry>
<para>Prompt</para></entry>
</row>
</thead>
<tbody>
<row>
<entry>
<para>C shell on UNIX and Linux systems</para></entry>
<entry>
<para><literal>machine_name%</literal></para></entry>
</row>
<row>
<entry>
<para>C shell superuser on UNIX and Linux systems</para></entry>
<entry>
<para><literal>machine_name#</literal></para></entry>
</row>
<row>
<entry>
<para>Bourne shell and Korn shell on UNIX and Linux systems</para></entry>
<entry>
<para><literal>$</literal></para></entry>
</row>
<row>
<entry>
<para>Bourne shell and Korn shell superuser on UNIX and Linux systems</para>
</entry>
<entry>
<para><literal>#</literal></para></entry>
</row>
<row>
<entry>
<para>Microsoft Windows command line</para></entry>
<entry>
<para><literal>C:\</literal></para></entry>
</row>
</tbody>
</tgroup>
</table>
</sect1>
<sect1 id="FQUVC"><title>Symbol Conventions</title>
<para>The following table explains symbols that might be used in this book.</para>
<table frame="topbot" id="FQUVR"><title>Symbol Conventions</title>
<tgroup cols="4" colsep="0" rowsep="0"><colspec colnum="1" colwidth="8*"
align="center"><colspec colnum="2" colwidth="28*"><colspec colnum="3"
colwidth="28*"><colspec colnum="4" colwidth="36*">
<thead>
<row rowsep="1">
<entry>
<para>Symbol</para></entry>
<entry>
<para>Description</para></entry>
<entry>
<para>Example</para></entry>
<entry>
<para>Meaning</para></entry>
</row>
</thead>
<tbody>
<row>
<entry>
<para><literal>[ ]</literal></para></entry>
<entry>
<para>Contains optional arguments and command options.</para></entry>
<entry>
<para><literal>ls [-l]</literal></para></entry>
<entry>
<para>The <literal>-l</literal> option is not required.</para></entry>
</row>
<row>
<entry>
<para><literal>{ | }</literal></para></entry>
<entry>
<para>Contains a set of choices for a required command option.</para></entry>
<entry>
<para><literal>-d {y|n}</literal></para></entry>
<entry>
<para>The <literal>-d</literal> option requires that you use either the <literal>
y</literal> argument or the <literal>n</literal> argument.</para></entry>
</row>
<row>
<entry>
<para><literal>${ }</literal></para></entry>
<entry>
<para>Indicates a variable reference.</para></entry>
<entry>
<para><literal>${com.sun.javaRoot}</literal></para></entry>
<entry>
<para>References the value of the <literal>com.sun.javaRoot</literal> variable.</para>
</entry>
</row>
<row>
<entry>
<para>-</para></entry>
<entry>
<para>Joins simultaneous multiple keystrokes.</para></entry>
<entry>
<para>Control-A</para></entry>
<entry>
<para>Press the Control key while you press the A key.</para></entry>
</row>
<row>
<entry>
<para>+</para></entry>
<entry>
<para>Joins consecutive multiple keystrokes.</para></entry>
<entry>
<para>Ctrl+A+N</para></entry>
<entry>
<para>Press the Control key, release it, and then press the subsequent keys.</para>
</entry>
</row>
<row>
<entry>
<para>&rarr;</para></entry>
<entry>
<para>Indicates menu item selection in a graphical user interface.</para>
</entry>
<entry>
<para>File &rarr; New &rarr; Templates</para></entry>
<entry>
<para>From the File menu, choose New. From the New submenu, choose Templates.</para>
</entry>
</row>
</tbody>
</tgroup>
</table>
</sect1>
</preface>

View File

@@ -0,0 +1,274 @@
<!--
Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
Portions copyright 1999 Netscape Communications Corporation. All
Rights Reserved.
The contents of this document are subject to the terms of the
Creative Commons Attribution-ShareAlike 2.5 license or any later
version (the "License"). You may not use this document except in
compliance with the License.
See the License for the specific language governing
permissions and limitations under the License. You can obtain
a copy of the License at
http://creativecommons.org/licenses/by-sa/2.5/legalcode.
-->
<chapter id="understanding-ldap"><title>Understanding LDAP</title>
<indexterm>
<primary>LDAP</primary>
</indexterm><indexterm>
<primary>Lightweight Directory Access Protocol</primary>
<see>LDAP</see></indexterm><highlights>
<para><firstterm>Lightweight Directory Access Protocol</firstterm> (LDAP)
is the Internet directory protocol. Developed at the University of Michigan
at Ann Arbor in conjunction with the Internet Engineering Task Force, LDAP
is a protocol for accessing and managing directory services.</para>
<itemizedlist>
<para>This chapter explains the LDAP protocol, and the concepts behind LDAP.
This chapter covers the following topics:</para>
<listitem><para><olink targetptr="how-ds-works">How Directory Services Work</olink></para>
</listitem>
<listitem><para><olink targetptr="how-ds-organizes-data">How LDAP Servers
Organize Directories</olink></para></listitem>
<listitem><para><olink targetptr="how-ldap-clients-servers-work">How LDAP
Clients and Servers Work</olink></para></listitem>
<listitem><para><olink targetptr="understanding-ldapv3">Understanding LDAP
v3</olink></para></listitem>
</itemizedlist>
</highlights>
<sect1 id="how-ds-works"><title>How Directory Services Work</title>
<indexterm>
<primary>directory</primary>
<secondary>definition of</secondary>
</indexterm><indexterm>
<primary>entries</primary>
<secondary>definition of</secondary>
</indexterm><indexterm>
<primary>attributes</primary>
<secondary>definition of</secondary>
</indexterm>
<para>A <firstterm>directory</firstterm> consists of <firstterm>entries</firstterm> that
contain descriptive information. For example, a directory might contain entries
that describe people or network resources, such as printers or fax machines.</para>
<para>The descriptive information is stored in the <firstterm>attributes</firstterm> of
the entry. Each attribute describes a specific type of information. For example,
attributes that describe a person might include her name, also referred to
as her common name (CN), telephone number, and email address.</para>
<para><indexterm>
<primary>entries</primary>
<secondary>example of</secondary>
</indexterm><indexterm>
<primary>attributes</primary>
<secondary>example of</secondary>
</indexterm>The entry for <literal>Barbara Jensen</literal> might have the
following attributes:</para>
<programlisting>cn: Barbara Jensen
mail: babs@example.com
telephoneNumber: 555-1212
roomNumber: 3995</programlisting>
<para>An attribute can have more than one value. For example, a person might
have two common names, both a formal name and also a nickname:</para>
<programlisting>cn: Barbara Jensen
cn: Babs Jensen
mail: babs@example.com
telephoneNumber: 555-1212
roomNumber: 3995</programlisting>
<para>Attributes can also contain binary data. For example, a person's attributes
might include her photo in JPEG format, a recording of her voice as an audio
file, or her SSL certificate.</para>
<para><indexterm>
<primary>directory service</primary>
<secondary>definition of</secondary>
</indexterm>A <firstterm>directory service</firstterm> is a distributed database
application for managing the entries and attributes in a directory. A directory
service also makes the entries and attributes available to users and other
applications.</para>
<para>&cnDirectoryServer; is an example of a directory service. For example,
a user might use the directory service to look up someone's telephone number.
Another application might use the directory service to retrieve a list of
email addresses.</para>
<para><indexterm>
<primary>LDAP servers</primary>
</indexterm><indexterm>
<primary>LDAP clients</primary>
</indexterm>LDAP is a protocol that defines a directory service and access
to that service. LDAP is based on a client-server model. LDAP servers provide
the directory service. LDAP clients use the directory service to access entries
and attributes.</para>
<para><indexterm>
<primary>LDAP servers</primary>
<secondary>example of</secondary>
</indexterm><indexterm>
<primary>LDAP clients</primary>
<secondary>example of</secondary>
</indexterm>&cnDirectoryServer; is an example of an LDAP server that manages
and provides information about users and organizational structures. Examples
of LDAP clients include Identity Manager, Access Manager, <trademark>Solaris</trademark> naming
services, Messaging Server, Portal Server, NameFinder, and the Mozilla mail
client. Such clients use &cnDirectoryServer; to find, update, and add information
about users.</para></sect1>
<sect1 id="how-ds-organizes-data"><title>How LDAP Servers Organize Directories</title>
<indexterm>
<primary>LDAP</primary>
<secondary>organization of data</secondary>
</indexterm><indexterm>
<primary>entries</primary>
<secondary>organization in LDAP</secondary>
</indexterm><indexterm>
<primary>LDAP servers</primary>
<secondary>how data is organized</secondary>
</indexterm>
<para>Because LDAP is intended to be a global directory service, data is organized
hierarchically, starting at a root and branching down into individual entries.</para>
<para>At the top level of the hierarchy, entries represent larger organizations.
Under larger organizations in the hierarchy, you might find entries for smaller
organizations. The hierarchy might end with entries for individual people,
or resources, as shown in the following figure.</para>
<figure id="hierarchy-in-ldap"><title>Hierarchy of Entries in a Directory</title>
<mediaobject>
<imageobject><imagedata entityref="hierovrw"></imageobject>
<textobject><simpara>Simple directory information tree with two organizational
unit entries and two user entries</simpara></textobject>
</mediaobject>
</figure>
<para><indexterm>
<primary>relative distinguished names (RDNs)</primary>
<secondary>definition of</secondary>
</indexterm><indexterm>
<primary>RDNs</primary>
<see>relative distinguished names (RDNs)</see></indexterm><indexterm>
<primary>distinguished names (DNs)</primary>
<secondary>definition of </secondary>
</indexterm><indexterm>
<primary>CNs</primary>
<see>common names (CNs)</see></indexterm><indexterm>
<primary>DNs</primary>
<see>distinguished names (DNs)</see></indexterm><indexterm>
<primary>common names (CNs)</primary>
</indexterm>Each entry is uniquely identified by a <firstterm>distinguished
name</firstterm> (DN). A DN includes a relative distinguished name (RDN),
that uniquely identifies the entry at that hierarchical level. For example, <literal>
bjensen</literal> and <literal>kjensen</literal> are different user IDs that
identify different entries at the same level. Following the RDN is a path
of names that trace the entry back to the root of the tree, such as <literal>ou=People,dc=example,dc=com
</literal>. <literal>DC</literal> is short for domain component. The full
DN for this example would be <literal>uid=bjensen,ou=People,dc=example,dc=com</literal>.
Here, <literal>uid</literal> is the user ID of the entry. <literal>ou</literal> is
short for organizational unit.</para>
<para><indexterm>
<primary>LDAP servers</primary>
<secondary>how data is distributed</secondary>
</indexterm>The data stored in a directory can be distributed among several
LDAP servers. For example, one LDAP server at <literal>Example.com</literal> might
contain entries representing North American organizational units and employees,
while another LDAP server might contain entries representing European organizational
units and employees.</para>
<para><indexterm>
<primary>LDAP servers</primary>
<secondary>how referrals work</secondary>
</indexterm><indexterm>
<primary>referrals</primary>
</indexterm>Some LDAP servers are set up to refer requests to other LDAP servers.
For example, if the LDAP server at <literal>Example.com</literal> receives
a request for information about an employee in a Pacific Rim branch, that
server can refer the request to the LDAP server at the Pacific Rim branch.
In this way, LDAP servers can appear to be a single source of directory information.
Even if an LDAP server does not contain the information you request, the server
can refer you to another server that does contain the information.</para>
</sect1>
<sect1 id="how-ldap-clients-servers-work"><title>How LDAP Clients and Servers
Work</title>
<indexterm>
<primary>LDAP servers</primary>
<secondary>LDAP clients and</secondary>
</indexterm><indexterm>
<primary>LDAP clients</primary>
<secondary>LDAP servers and</secondary>
</indexterm><indexterm>
<primary>LDAP clients</primary>
<secondary>operations performed by</secondary>
</indexterm>
<para>In the LDAP client-server model, LDAP servers such as &cnDirectoryServer;
make information about people, organizations, and resources accessible to
LDAP clients. LDAP defines operations that clients use to search and update
the directory.</para>
<itemizedlist>
<para>An LDAP client can perform these operations, among others:</para>
<listitem><para>Search for and retrieve entries from the directory</para>
</listitem>
<listitem><para>Add new entries to the directory</para></listitem>
<listitem><para>Update entries in the directory</para></listitem>
<listitem><para>Delete entries from the directory</para></listitem>
<listitem><para>Rename entries in the directory</para></listitem>
</itemizedlist>
<para>For example, to update an entry, an LDAP client submits the distinguished
name of the entry with updated attribute information to the LDAP server. The
LDAP server uses the distinguished name to find the entry. The server then
performs a modify operation to update the entry in the directory.</para>
<para><indexterm>
<primary>LDAP servers</primary>
<secondary>connecting with LDAP clients</secondary>
</indexterm><indexterm>
<primary>LDAP clients</primary>
<secondary>connecting with LDAP servers</secondary>
</indexterm>To perform any of these LDAP operations, an LDAP client needs
to establish a connection with an LDAP server. The LDAP protocol specifies
the use of TCP/IP port number 389, although servers can run on other ports.</para>
<para><indexterm>
<primary>LDAP servers</primary>
<secondary>authentication</secondary>
</indexterm><indexterm>
<primary>LDAP clients</primary>
<secondary>authentication</secondary>
</indexterm>The LDAP protocol also defines a simple method for authentication.
LDAP servers can be set up to restrict permissions to the directory. Before
an LDAP client can perform an operation on an LDAP server, the client must
authenticate to the server. Clients typically authenticate by supplying a
distinguished name and password. If the user identified by the distinguished
name does not have permission to perform the operation, the server does not
execute the operation.</para></sect1>
<sect1 id="understanding-ldapv3"><title>Understanding LDAP v3</title>
<indexterm>
<primary>LDAP</primary>
<secondary>version 3</secondary>
</indexterm>
<para><ulink url="http://www.ietf.org/rfc/rfc4511.txt" type="text_url">RFC
4511</ulink> specifies LDAP version 3. Use this version of the protocol when
writing new client applications.</para>
<para>Many LDAP servers continue to support LDAP version 2 for use with legacy
clients. This version of the protocol is specified in <ulink
url="http://www.ietf.org/rfc/rfc1777.txt" type="text_url">RFC 1777</ulink>.</para>
<itemizedlist>
<para>LDAP v3 includes new features not present in version 2:</para>
<listitem><para>Clients and servers can specify <firstterm>controls</firstterm> that
extend the functionality of an LDAP operation.</para></listitem>
<listitem><para>Clients can request that the server perform <firstterm>extended
operations</firstterm>, operations not included in the list of standard LDAP
operations.</para></listitem>
<listitem><para>Clients can use <firstterm>Simple Authentication and Security
Layer</firstterm> (SASL) mechanisms to authenticate to the directory. SASL
is specified in <ulink url="http://www.ietf.org/rfc/rfc4422.txt" type="text_url">
RFC 4422</ulink>.</para></listitem><?Pub Caret>
<listitem><para>Servers, known as <firstterm>Directory System Agents</firstterm> (DSAs),
have <firstterm>DSA-specific entries</firstterm> (DSEs). DSEs provide information
about the versions of the LDAP protocol that the server supports. DSEs also
provide a list of the controls, extended operations, and SASL mechanisms supported
by the server. Finally, DSEs specify the naming contexts of the server. Naming
contexts are portions of the directory information tree managed by the server.</para>
</listitem>
<listitem><para>Servers make their <firstterm>schemas</firstterm>, which define
the object classes, attributes, syntaxes, and matching rules enforced by the
directory, available to clients through the root DSE.</para></listitem>
<listitem><para><indexterm>
<primary>UTF-8</primary>
<secondary>support of</secondary>
</indexterm>Both client and server applications can support data in UTF-8. <firstterm>
UTF-8</firstterm> is a transformation format of the Universal Character Set
standard. UTF-8 is specified in <ulink url="http://www.ietf.org/rfc/rfc3269.txt"
type="text_url">RFC 3269</ulink>. With UTF-8, clients can request and receive
data that is tagged with language information.</para></listitem>
</itemizedlist>
</sect1>
</chapter>

View File

@@ -0,0 +1,108 @@
<!--
Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
Portions copyright 1999 Netscape Communications Corporation. All
Rights Reserved.
The contents of this document are subject to the terms of the
Creative Commons Attribution-ShareAlike 2.5 license or any later
version (the "License"). You may not use this document except in
compliance with the License.
See the License for the specific language governing
permissions and limitations under the License. You can obtain
a copy of the License at
http://creativecommons.org/licenses/by-sa/2.5/legalcode.
-->
<!DOCTYPE BOOK PUBLIC "-//OASIS//DTD DocBook V4.3//EN" [
<!ENTITY abstract SYSTEM "abstract.sgm">
<!ENTITY best-practices SYSTEM "best-practices.sgm">
<!ENTITY BookTitle "Programmer's Guide">
<!ENTITY choose-api SYSTEM "choose-api.sgm">
<!ENTITY cnDirectoryServer "Directory Server">
<!ENTITY DirectorySDKForC "Directory SDK for C">
<!ENTITY DirectorySDKForJava "Directory SDK for Java">
<!ENTITY entries SYSTEM "figures/entries.eps" NDATA eps>
<!ENTITY hier1lvl SYSTEM "figures/hier1lvl.eps" NDATA eps>
<!ENTITY hierbase SYSTEM "figures/hierbase.eps" NDATA eps>
<!ENTITY hierovrw SYSTEM "figures/hierovrw.eps" NDATA eps>
<!ENTITY hiersrch SYSTEM "figures/hiersrch.eps" NDATA eps>
<!ENTITY jdk-adding SYSTEM "jdk-adding.sgm">
<!ENTITY jdk-asynchronous SYSTEM "jdk-asynchronous.sgm">
<!ENTITY jdk-common-classes SYSTEM "jdk-common-classes.sgm">
<!ENTITY jdk-comparing SYSTEM "jdk-comparing.sgm">
<!ENTITY jdk-controls SYSTEM "jdk-controls.sgm">
<!ENTITY jdk-extended-ops SYSTEM "jdk-extended-ops.sgm">
<!ENTITY jdk-filter-conf SYSTEM "jdk-filter-conf.sgm">
<!ENTITY jdk-ldap-urls SYSTEM "jdk-ldap-urls.sgm">
<!ENTITY jdk-quickstart SYSTEM "jdk-quickstart.sgm">
<!ENTITY jdk-sasl SYSTEM "jdk-sasl.sgm">
<!ENTITY jdk-searching SYSTEM "jdk-searching.sgm">
<!ENTITY jdk-server-info SYSTEM "jdk-server-info.sgm">
<!ENTITY jdk-ssl SYSTEM "jdk-ssl.sgm">
<!ENTITY jdk-writing-client SYSTEM "jdk-writing-client.sgm">
<!ENTITY legal SYSTEM "legal.sgm">
<!ENTITY license SYSTEM "license.txt">
<!ENTITY preface SYSTEM "preface.sgm">
<!ENTITY understanding-ldap SYSTEM "understanding-ldap.sgm">
<!NOTATION graphic SYSTEM "graphic">
]>
<book lang="en">
<title>Programmer's Guide for LDAP Java SDK</title>
<bookinfo>
<authorgroup><author><firstname>Mark</firstname><surname>Craig</surname>
</author></authorgroup>
<pubdate>June 2007</pubdate>
<publisher>
<publishername>Sun Microsystems, Inc.</publishername>
<address>
<street>4150 Network Circle</street>
<city>Santa Clara</city><state>CA</state><postcode>95054</postcode>
<country>U.S.A.</country>
</address></publisher>
<copyright><year>2000-2007</year><holder>Sun Microsystems, Inc. All Rights Reserved.</holder></copyright>
<legalnotice><para><emphasis role="strong">License</emphasis> -
<emphasis>The contents of this document are subject to the terms of
the Creative Commons Attribution-ShareAlike 2.5 license or any later version (the
"License"). You may not use this document except in compliance with
the License.</emphasis></para>
<para><emphasis>See the License for the specific language governing
permissions and limitations under the License. The full text of the
License is provided at the end of this
document.</emphasis></para>&legal;
</legalnotice>
<abstract>&abstract;
</abstract>
</bookinfo>&preface;
&understanding-ldap;
&choose-api;
&best-practices;
&jdk-quickstart;
&jdk-writing-client;
&jdk-common-classes;
&jdk-searching;
&jdk-filter-conf;
&jdk-adding;
&jdk-comparing;
&jdk-ldap-urls;
&jdk-server-info;
&jdk-ssl;
&jdk-controls;
&jdk-sasl;
&jdk-extended-ops;
&jdk-asynchronous;
<appendix id="share-alike">
<title>Creative Commons Attribution-ShareAlike 2.5</title>
<para>The contents of this document are subject to the terms of the
Creative Commons Attribution-ShareAlike 2.5 license (the
"License"). You may not use this document except in compliance with
the License.</para>
<para>See the License for the specific language governing permissions
and limitations under the License. The full text of the License is as
follows.</para>
<programlisting>&license;</programlisting>
</appendix>
<index><title>Index</title>
<indexentry><primaryie></primaryie></indexentry></index>
</book>

View File

@@ -0,0 +1,20 @@
<!--
Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
Portions copyright 1999 Netscape Communications Corporation. All
Rights Reserved.
The contents of this document are subject to the terms of the
Creative Commons Attribution-ShareAlike 2.5 license or any later
version (the "License"). You may not use this document except in
compliance with the License.
See the License for the specific language governing
permissions and limitations under the License. You can obtain
a copy of the License at
http://creativecommons.org/licenses/by-sa/2.5/legalcode.
-->
<para>This <citetitle>&BookTitle;</citetitle> shows you how to
create LDAP client applications in the Java language to connect to LDAP servers.
This guide also shows you how to perform standard LDAP operations.</para>

View File

@@ -0,0 +1,378 @@
<!--
Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
Portions copyright 1999 Netscape Communications Corporation. All
Rights Reserved.
The contents of this document are subject to the terms of the
Creative Commons Attribution-ShareAlike 2.5 license or any later
version (the "License"). You may not use this document except in
compliance with the License.
See the License for the specific language governing
permissions and limitations under the License. You can obtain
a copy of the License at
http://creativecommons.org/licenses/by-sa/2.5/legalcode.
-->
<chapter id="best-practices-overview"><title>Best Practices for
Writing Client Applications</title>
<highlights>
<itemizedlist>
<para>This chapter includes best practices for developing client applications
and cover the following topics:</para>
<listitem><para><olink targetptr="best-ldapv3">Creating Your Application</olink></para>
</listitem>
<listitem><para><olink targetptr="best-troubleshooting">Troubleshooting Problems</olink></para>
</listitem>
</itemizedlist>
</highlights>
<sect1 id="best-ldapv3"><title>Creating Your Application</title>
<itemizedlist>
<para>This section identifies practices to observe when creating directory
client applications.</para>
<listitem><para><olink targetptr="specify-ldapv3">Specify LDAP v3</olink></para>
</listitem>
<listitem><para><olink targetptr="best-authenticating">Authenticate Correctly</olink></para>
</listitem>
<listitem><para><olink targetptr="best-connect">Limit Connection Overhead</olink></para>
</listitem>
<listitem><para><olink targetptr="best-inactivity-timeouts">Handle Potential
Inactivity Timeouts</olink></para></listitem>
<listitem><para><olink targetptr="best-entries">Retrieve Entries Intelligently</olink></para>
</listitem>
<listitem><para><olink targetptr="best-filters">Write Simple, Conforming LDAP
Filters</olink></para></listitem>
<listitem><para><olink targetptr="best-mods">Performing Specific Modifications</olink></para>
</listitem>
<listitem><para><olink targetptr="best-rc">Trust Result Codes</olink></para>
</listitem>
<listitem><para><olink targetptr="best-groups">Limit Dealings With Groups
and Roles</olink></para></listitem>
<listitem><para><olink targetptr="best-dse">Read the DSE</olink></para>
</listitem>
<listitem><para><olink targetptr="best-resources">Use Resource-Intensive Features Sparingly</olink></para></listitem>
<listitem><para><olink targetptr="best-dit">Avoid Hard Coding Certain Information
</olink></para></listitem>
<listitem><para><olink targetptr="best-schema">Define Schemas Only When Necessary
</olink></para></listitem>
<listitem><para><olink targetptr="best-refer">Handle Referrals</olink></para>
</listitem>
<listitem><para><olink targetptr="best-not-rdbm">Treat a Directory as a Directory
</olink></para></listitem>
</itemizedlist>
<sect2 id="specify-ldapv3"><title>Specify LDAP v3</title>
<itemizedlist>
<para>Many client libraries default to LDAP v2, but you can elect to use LDAP
v3. To benefit from LDAP v3 features, you can set up the connection, and then
authenticate explicitly using LDAP v3.</para>
<listitem><para>With JNDI, you could use LDAP v3 as shown here.</para>
<programlisting role="fragment">import java.util.Hashtable;
import javax.naming.ldap.InitialLdapContext;
Hashtable env = new Hashtable();
env.put("java.naming.ldap.version", "<emphasis>3</emphasis>");
InitialLdapContext ctx = new InitialLdapContext(env, null);</programlisting>
</listitem>
<listitem><para>With &DirectorySDKForC;, you could use LDAP v3 as shown
here.</para>
<programlisting role="fragment">#include "ldap.h"
int version = <emphasis>LDAP_VERSION3</emphasis>;
ldap_set_option( NULL, LDAP_OPT_PROTOCOL_VERSION, &amp;version );</programlisting>
<para>&DirectorySDKForC; uses LDAP v3 by default.</para></listitem>
<listitem><para>With &DirectorySDKForJava;, you could use LDAP v3 as shown
here.</para>
<programlisting role="fragment">import netscape.ldap.LDAPConnection;
LDAPConnection ld = new LDAPConnection();
ld.setOption(LDAPv3.PROTOCOL_VERSION, new Integer(<emphasis>3</emphasis>));
</programlisting>
</listitem>
</itemizedlist>
</sect2>
<sect2 id="best-authenticating"><title>Authenticate Correctly</title>
<para>Your SDK uses terminology that is slightly different from LDAP v3. In
LDAP v3, you connect, then you bind and perform LDAP operations, then you
unbind and disconnect. The bind is the authentication operation in LDAP. Your
application can hold onto a connection but change the authentication credentials
by using the bind operation again.</para>
<para>Some directories do not allow anonymous access, even for reads. When
you build your application, keep the option that allows users to authenticate
to the directory. Furthermore, the information sent across the network can
be sensitive. You can protect sensitive data by allowing the application to
secure the connection by using Secure Sockets Layer (SSL) or Start Transport
Layer Security (TLS).</para>
<para>If your application needs to authenticate, obtain a regular account
to authenticate with the directory, rather than using the directory superuser
account such as <literal>cn=Directory Manager</literal>. When you authenticate
as directory superuser, you often bypass normal access control mechanisms.
Bypassing normal access control renders auditing directory access more difficult.
</para>
<para>When authenticating, have your application use SSL or SASL DIGEST MD5
to avoid sending passwords over the network in clear text. Furthermore, when
using password-based authentication, have your application check password
policy controls, especially to determine when a password must be renewed.</para>
</sect2>
<sect2 id="best-connect"><title>Limit Connection Overhead</title>
<para>A new connection requires system resources. The LDAP model allows you
to reuse connections by binding again with a different identity on the same
connection. Thus, you can avoid the costs of new connections, particularly
negotiated connections such as connections that use SSL, by reusing connections.
Your application can use a pool of connections, rebinding when necessary.
Your application can alternatively use the proxy authorization control to
remain authenticated as the application but perform operations on behalf of
a particular user.</para>
<para>When establishing a connection, your application can provide alternate
server host names and port numbers to facilitate failover that is transparent
to the application. You can also set time limits for LDAP operations to avoid
getting blocked.</para>
<para>When finished with a connection, your application should perform an
unbind.</para></sect2>
<sect2 id="best-inactivity-timeouts"><title>Handle Potential Inactivity Timeouts</title>
<para>Most network equipment can use timeouts to drop stale connections, ensuring
the equipment keeps a maximum number of connections that are available.</para>
<para>If your application pools connections or opens connections for persistent
search, than guard against timeouts that drop those connections. Use the connections
occasionally to reset inactivity timers present in the network.</para>
<para>Alternatively, if you have control over the connection, consider disabling
inactivity time outs for your applications that need to keep persistent connections
open. Load balancers and proxy software often use inactivity timeouts.</para>
</sect2>
<sect2 id="best-entries"><title>Retrieve Entries Intelligently</title>
<para>&cnDirectoryServer; typically responds quickly to requests for entries.
Yet, &cnDirectoryServer; can respond most quickly when your application asks
it to do only necessary work. If you need to read only a few attributes in
an entry, request each attribute explicitly. Avoid reading the entire entry,
then parsing the entire entry to obtain the required data.</para>
<para>Furthermore, when you do request attributes in an entry, retrieve all
the required attributes at once. Each new request involves a new operation
on the server.</para>
<para>If any of the attributes that you require are operational attributes,
you must request those attributes specifically. Such attributes are identifiable
in directory schema by their <literal>USAGE</literal>, which is <literal>directoryOperation
</literal> or <literal>dsaOperation</literal>.</para>
<para>When retrieving entries and attributes, recognize that you might not
have access to all the attributes that exist.</para></sect2>
<sect2 id="best-filters"><title>Write Simple, Conforming LDAP Filters</title>
<indexterm>
<primary>LDAP filters</primary>
<secondary>writing</secondary>
</indexterm>
<para>The best filters use attributes that are indexed according to the way
the attributes are indexed. For example, if <literal>employeeNumber</literal> is
indexed for equality, your filter should be an equality filter such as <literal>(employeeNumber=123456)
</literal>. Do not use a substring filter instead.</para>
<para>Avoid deeply nested complex filters when you can. When you must use
complex filters, place the most specific filters first to narrow the list
of candidate entries the directory must check. For best results, use <literal>not
</literal>, <literal>!</literal>, only with <literal>and</literal>, <literal>&amp;
</literal>, for example <literal>(&amp;(cn=Barbara)(!(sn=Jensen)))</literal>.
When you use <literal>not</literal> with <literal>or</literal> in a filter,
the directory must construct a candidate list of everything except what your
filter specifies.</para></sect2>
<sect2 id="best-mods"><title>Performing Specific Modifications</title>
<para>Modifications are atomic on the entry to which the modifications apply.
When modifying multivalued attributes, delete and replace specific values.
Do not replace an entire list of multiple values to change only a few values.
Replacing specific values is particularly good practice when the changes must
be replicated across a set of servers.</para>
<para>Moreover, when you have large values to store in an attribute, store
a reference to the data instead of storing the data object.</para></sect2>
<sect2 id="best-rc"><title>Trust Result Codes</title>
<indexterm>
<primary>result codes</primary>
<secondary>trust</secondary>
</indexterm>
<para>&cnDirectoryServer; trades tight consistency across replica servers
for very high performance, availability, and scalability. By allowing <firstterm>
loose consistency</firstterm> of data across sets of replica servers, &cnDirectoryServer; instances
can respond very quickly to your application. Yet, data replication is not
instantaneous. A short but detectable delay can ensue after a server returns
success for a write operation, but before the effects are seen on other replicas.
</para>
<para>Therefore, when your application receives a result code from &cnDirectoryServer; to
indicate that an operation was successful, your application should trust the
result code. When application requests are balanced across replicas, reading
from another replica might result in errors due to a slight delay in replication.
</para></sect2>
<sect2 id="best-groups"><title>Limit Dealings With Groups and Roles</title>
<indexterm>
<primary>groups</primary>
<secondary>working with</secondary>
</indexterm>
<para>When you want to know whether an account belongs to a group or a role,
read only the necessary attribute values. Do not read the entire list of group
members.</para>
<orderedlist>
<para>For <literal>dynamic groups</literal>, do the following:</para>
<listitem><para>Read the URL from the group definition.</para></listitem>
<listitem><para>Examine the host, DN, and scope of the URL.</para></listitem>
<listitem><para>Apply the filter part of the URL to the entry for the account.</para>
</listitem>
</orderedlist>
<para><indexterm>
<primary>roles</primary>
<secondary>working with</secondary>
</indexterm>For <literal>roles</literal>, compare the DN of the role to the <literal>
nsRole</literal> attribute of the entry for the account, such as <literal>(nsrole=cn=management,ou=people,dc=example,dc=com)
</literal>. You can then retrieve all the values of the <literal>nsRole</literal> attribute
for the account.</para></sect2>
<sect2 id="best-dse"><title>Read the DSE</title>
<indexterm>
<primary>DSE, root</primary>
<secondary>reading</secondary>
</indexterm>
<para>The root DSE is the entry that is retrieved by <command>ldapsearch -b
"" -s base "(objectclass=*)"</command>. The root DSE describes server capabilities.
The root DSE contains information about supported LDAP protocol versions,
naming contexts (suffixes), LDAP v3 controls, LDAP v3 extensions, and authentication
mechanisms. The root DSE can contain information about the server version.</para>
<para>Some directory administrators protect access to the root DSE. Yet, applications
might read the root DSE to confirm that the server in fact supports functionality
required by applications.</para></sect2>
<sect2 id="best-resources"><title>Use Resource-Intensive Features Sparingly</title>
<para>Directories offer powerful features that can nevertheless place a heavy
load on the server. Two such features are persistent search, and server-side
sorting.</para>
<para>Persistent search lets you start a search that does not stop when complete,
but instead allows you to receive updates when entries are modified. To provide
this feature, the server must handle your search when anything happens to
an entry in its scope.</para>
<para>Server-side sorting requires that the server sort the entries that are
returned during a search. Instead of returning entries as quickly as possible,
the server must therefore get the list to return, and sort the list.</para>
</sect2>
<sect2 id="best-dit"><title>Avoid Hard Coding Certain Information</title>
<para>The container entry for a subtree might be not be identical on different
directories. Rather than hard code the container entry throughout your application,
locate the container entry. Then navigate beneath the container entry in the
tree.</para>
<para>Object classes and attribute types for the same information can also
differ from directory to directory. Use configuration files, properties files,
or other easily modifiable variables rather than hard coding object class
and attribute type identifiers into your application.</para>
<para>Be aware as well that object class and attribute type identifiers are <emphasis>
not case-sensitive</emphasis> in LDAP. Your application should therefore recognize
that <literal>inetOrgPerson</literal> and <literal>inetorgperson</literal> are
equivalent, as are <literal>isMemberOf</literal> and <literal>ismemberof</literal>.
</para></sect2>
<sect2 id="best-schema"><title>Define Schemas Only When Necessary</title>
<indexterm>
<primary>schema</primary>
<secondary>defining</secondary>
</indexterm>
<para>Schemas define the object classes and attribute types that are recognized
by the directory. If your application can use a standard schema, use the standard
schema. &cnDirectoryServer; contains schemas that define numerous standard
object classes, and attribute types.</para>
<itemizedlist>
<para>When you must define your own schema objects, follow these guidelines:</para>
<listitem><para>Extend existing object classes by using <literal>AUXILIARY</literal> classes.
</para></listitem>
<listitem><para>Create new attributes rather than redefining existing attributes.
</para><para>Other applications might depend on existing attributes to keep
their existing semantics.</para></listitem>
<listitem><para>Obtain new object identifiers for the schema elements you
define, rather than reusing existing object identifiers.</para></listitem>
<listitem><para>Obtain new names for the schema elements you define, rather
than reusing existing names.</para></listitem>
<listitem><para>Update &cnDirectoryServer; schema over LDAP if you can.</para>
</listitem>
</itemizedlist>
</sect2>
<sect2 id="best-refer"><title>Handle Referrals</title>
<indexterm>
<primary>referrals</primary>
<secondary>following</secondary>
</indexterm>
<para>LDAP v3 allows directories that are unable to handle your request to
refer your application to other directories. Your application should follow
those referrals.</para>
<para>When following referrals, realize that authentication procedures might
not be exactly the same on different directories. Also, directories that refer
to each other could potentially cause a referral loop. With &DirectorySDKForC; and &DirectorySDKForJava;,
you can limit referral hops to prevent your application from being referred
endlessly from one directory to another directory. The JNDI interface enables
you to follow referrals automatically.</para></sect2>
<sect2 id="best-not-rdbm"><title>Treat a Directory as a Directory</title>
<para>A directory is typically a repository for identity data, and for information
that you expect to keep for awhile and read often. You might typically find
relational databases better adapted to hold transient data such as session
keys and presence information, or voluminous accumulated data such as application
logs.</para></sect2>
</sect1>
<sect1 id="best-troubleshooting"><title>Troubleshooting Problems</title>
<para>This section covers basic troubleshooting approaches and techniques
to use when developing directory client applications. You can check result
codes, check server log files, and inspect network packets.</para>
<sect2 id="trouble-rc"><title>Check Result Codes</title>
<indexterm>
<primary>troubleshooting</primary>
<secondary>result codes</secondary>
</indexterm>
<para>When an LDAP request from your application fails on the server, the
server sends back a result code, and possibly an explanatory message. Your
application should check the result codes, and for explanatory messages. Common
failure result codes include the following, which are expressed as decimal
values. Others result codes are defined as well.</para>
<variablelist>
<varlistentry><term><errorcode>1</errorcode></term>
<listitem><para>LDAP operations error. The server encountered an error while
processing your request.</para>
</listitem>
</varlistentry>
<varlistentry><term><errorcode>32</errorcode></term>
<listitem><para>No such object. The entry is not present on the server. Also,
no referral is defined for the entry.</para>
</listitem>
</varlistentry>
<varlistentry><term><errorcode>49</errorcode></term>
<listitem><para>Invalid credentials. Your application failed to authenticate
properly.</para>
</listitem>
</varlistentry>
<varlistentry><term><errorcode>53</errorcode></term>
<listitem><para>LDAP unwilling to perform. The directory does not support
the request. Alternatively, the directory is not currently in a state in which
to complete your request. For example, the directory might be in read-only
mode when your application requests a modification.</para>
</listitem>
</varlistentry>
<varlistentry><term><errorcode>65</errorcode></term>
<listitem><para>Object class violation. Your write request would cause an
entry to no longer conform to the schema defined for the directory.</para>
</listitem>
</varlistentry>
<varlistentry><term><errorcode>68</errorcode></term>
<listitem><para>Already exists. Your application is requesting to add an entry
that has the same DN as an entry already present in the directory.</para>
</listitem>
</varlistentry>
</variablelist>
<para><ulink url="http://ietf.org/rfc/rfc4511.txt" type="text_url">RFC 4511</ulink> defines
LDAP error codes, as does <olink targetptr="bdaxx">Chapter&nbsp;22, Directory
SDK for C Result Codes</olink>.</para></sect2>
<sect2 id="trouble-logs"><title>Check Server Log Files</title>
<indexterm>
<primary>troubleshooting</primary>
<secondary>log files</secondary>
</indexterm>
<para>&cnDirectoryServer; logs messages related to server operation in its <filename>
logs/errors</filename> file. If you have access to this file, you might find
useful troubleshooting information there.</para>
<para>When debugging your application against &cnDirectoryServer;, you can
adjust the log level, as well. See the server documentation for instructions.</para>
</sect2>
<sect2 id="trouble-network-tools"><title>Inspect Network Packets</title>
<indexterm>
<primary>troubleshooting</primary>
<secondary>decoding packets</secondary>
</indexterm>
<para>Although LDAP is not a textual protocol, tools such as <citerefentry>
<refentrytitle>snoop</refentrytitle><manvolnum>1M</manvolnum></citerefentry>, <command>
ethereal</command>, and <command>tcpdump</command> can decode the packets,
sometimes providing you with important debugging information.</para></sect2>
</sect1>
</chapter>

View File

@@ -0,0 +1,98 @@
<!--
Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
Portions copyright 1999 Netscape Communications Corporation. All
Rights Reserved.
The contents of this document are subject to the terms of the
Creative Commons Attribution-ShareAlike 2.5 license or any later
version (the "License"). You may not use this document except in
compliance with the License.
See the License for the specific language governing
permissions and limitations under the License. You can obtain
a copy of the License at
http://creativecommons.org/licenses/by-sa/2.5/legalcode.
-->
<chapter id="best-practices-choose"><title>Choosing a Client
SDK</title>
<highlights>
<para>This chapter discusses software development kits to help you select
the appropriate directory SDK for your particular situation.</para>
<itemizedlist>
<para>This chapter covers the following topics:</para>
<listitem><para><olink targetptr="choose-jndi">Java Naming and Directory Interface
</olink></para></listitem>
<listitem><para><olink targetptr="choose-ljdk">Directory SDK for Java</olink></para>
</listitem>
<listitem><para><olink targetptr="choose-cdsk">Directory SDK for C</olink></para>
</listitem>
<listitem><para><olink targetptr="choose-solaris-libldap">Operating System libldap Library</olink></para></listitem>
<listitem><para><olink targetptr="choose-other">Support for Other Programming
Languages</olink></para></listitem>
</itemizedlist>
</highlights>
<sect1 id="choose-jndi"><title>Java Naming and Directory Interface</title>
<indexterm>
<primary>Java Naming and Directory Interface</primary>
</indexterm><indexterm>
<primary>JNDI</primary>
<see>Java Naming and Directory Interface</see></indexterm>
<para>Java Naming and Directory Interface (JNDI) technology supports directory
access through LDAP and DSML v2 from <trademark>Java</trademark> applications,
and is part of the Java platform. With JNDI, you can build powerful, portable,
directory-enabled applications that do not depend on classes outside the Java
platform.</para>
<para>JNDI provides an abstract model that lets you access not only directories,
but also naming services in general, including DNS, RMI, COS, and file systems.</para>
<para>For information about JNDI, see <ulink
url="http://java.sun.com/products/jndi/" type="url"></ulink>. The <citetitle>JNDI
Tutorial</citetitle> contains descriptions and examples of how to use JNDI.
The tutorial is at <ulink url="http://java.sun.com/products/jndi/tutorial/"
type="url"></ulink>.</para></sect1>
<sect1 id="choose-cdsk"><title>&DirectorySDKForC;</title>
<para>&DirectorySDKForC; lets you access LDAP directories from C and C++
applications. &DirectorySDKForC; applications depend on &DirectorySDKForC; libraries,
which are available on a wide range of platforms.</para>
<para>&DirectorySDKForC; was the subject of Internet-Draft work but never
became a standard API. &DirectorySDKForC; closely follows LDAP v3, providing
support for core LDAP operations and for LDAP v3 extensions and widely used
controls. &DirectorySDKForC; offers a rich API to the C and C++ developer
familiar with the LDAP model. &cnDirectoryServer; relies on &DirectorySDKForC;.
</para>
<para>This document demonstrates how to use &DirectorySDKForC;. &DirectorySDKForC; code
is published in open source form as part of the Mozilla Directory SDK project.</para>
</sect1>
<sect1 id="choose-ljdk"><title>&DirectorySDKForJava;</title>
<para>&DirectorySDKForJava; lets you access LDAP directories from Java
applications, but it is not part of the Java platform.</para>
<para>Although not a standard API, &DirectorySDKForJava; closely follows
LDAP v3 idioms. &DirectorySDKForJava; provides a rich set of interfaces
to the Java developer familiar with the LDAP model.</para>
<para>This document demonstrates how to use &DirectorySDKForJava;. &DirectorySDKForJava; code
is published in open source form as part of the Mozilla Directory SDK project.</para>
</sect1>
<sect1 id="choose-solaris-libldap"><title>Operating System <filename>libldap</filename> Library
</title>
<indexterm>
<primary>libraries</primary>
<secondary><filename>libldap</filename></secondary>
</indexterm><indexterm>
<primary><filename>libldap</filename></primary>
</indexterm>
<para>The native LDAP library on <trademark>Solaris</trademark> systems provides
essentially the same API as &DirectorySDKForC;. Many &DirectorySDKForC; need
only be recompiled to work with <filename>libldap</filename>.</para>
<para>The LDAP library is sometimes not compatible with <filename>libldap</filename> on
many GNU/Linux distributions. Many GNU/Linux distributions provide OpenLDAP
support by default.</para></sect1>
<sect1 id="choose-other"><title>Support for Other Programming Languages</title>
<para>Support for directory access is available in a number of contexts where
you do not choose to use the C or Java languages.</para>
<para>For example, Perl has the PerLDAP module and the Net::LDAP collection
of modules. Python has the <literal>python-ldap</literal> package. PHP can
be compiled with LDAP support. Ruby has the Ruby/LDAP extension module. In
many cases, you can choose the language that fits the task and find that LDAP
support is available.</para></sect1>
</chapter>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,677 @@
<!--
Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
Portions copyright 1999 Netscape Communications Corporation. All
Rights Reserved.
The contents of this document are subject to the terms of the
Creative Commons Attribution-ShareAlike 2.5 license or any later
version (the "License"). You may not use this document except in
compliance with the License.
See the License for the specific language governing
permissions and limitations under the License. You can obtain
a copy of the License at
http://creativecommons.org/licenses/by-sa/2.5/legalcode.
-->
<chapter id="adding"><title>Adding, Updating, and Deleting Entries With &DirectorySDKForJava;</title>
<highlights>
<para>This chapter explains how to use the LDAP Java classes to add, modify,
delete, and rename entries in the directory.</para>
<itemizedlist>
<para>This chapter covers the following topics:</para>
<listitem><para><olink targetptr="add-entry">Adding an Entry With Directory
SDK for Java</olink></para></listitem>
<listitem><para><olink targetptr="mod-entry">Modifying an Entry With Directory SDK for Java</olink></para></listitem>
<listitem><para><olink targetptr="del-entry">Deleting an Entry With Directory
SDK for Java</olink></para></listitem>
<listitem><para><olink targetptr="rename-entry">Renaming an Entry With Directory
SDK for Java</olink></para></listitem>
</itemizedlist>
</highlights>
<sect1 id="add-entry"><title>Adding an Entry With &DirectorySDKForJava;</title>
<indexterm>
<primary>adding</primary>
<secondary>entries</secondary>
</indexterm><indexterm>
<primary>entries</primary>
<secondary>adding</secondary>
</indexterm>
<orderedlist>
<para>To add an entry to the directory, follow this general procedure:</para>
<listitem><para>Create individual attributes for the entry.</para></listitem>
<listitem><para>Create the set of attributes that make up the entry and add
each of the attributes to this set.</para></listitem>
<listitem><para>Create the new entry, specifying a unique distinguished name
(DN) to identify the entry and the set of attributes that make up the entry.</para>
</listitem>
<listitem><para>Add the new entry to directory.</para></listitem></orderedlist>
<sect2 id="add-new-attr"><title>Creating a New Attribute</title>
<para>An attribute can have a single value or multiple values. An attribute
can contain string values or binary data. In the LDAP Java classes, an attribute
is represented by an <classname>LDAPAttribute</classname> object.</para>
<para>To create a new attribute, use the <classname>LDAPAttribute</classname> constructor.
You can specify a single string value, multiple string values, or a binary
value when constructing the object.</para>
<para>For example, the following section of code creates a new object for
the attribute <literal>cn</literal> with the value <literal>Jane St. Clair</literal>.
</para>
<programlisting>LDAPAttribute attr = new LDAPAttribute("cn", "Jane St. Clair");</programlisting>
<para>The following section of code creates an attribute <literal>objectclass</literal> with
the values <literal>top</literal>, <literal>person</literal>, <literal>organizationalPerson
</literal>, and <literal>inetOrgPerson</literal>.</para>
<programlisting>String objectclasses[] = {"top", "person", "organizationalPerson",
"inetOrgPerson"};
LDAPAttribute attr = new LDAPAttribute("objectclass", objectclasses);</programlisting>
<para>You can also add string or binary values to an <classname>LDAPAttribute</classname> object
by invoking the <literal>addValue</literal> method.</para></sect2>
<sect2 id="add-new-set"><title>Creating a New Attribute Set</title>
<para>To specify the set of attributes in an entry, you need to create an
attribute set. In the LDAP Java classes, a set of one or more attributes is
represented by an <classname>LDAPAttributeSet</classname> object.</para>
<para>To create a new attribute set, use the <classname>LDAPAttributeSet</classname> constructor.
Invoke the <literal>add</literal> method to add <classname>LDAPAttribute</classname> objects
to the set.</para>
<programlisting>LDAPAttribute attr1 = new LDAPAttribute("cn", "Jane St. Clair");
String objectclasses[] = {"top", "person", "organizationalPerson",
"inetOrgPerson"};
LDAPAttribute attr2 = new LDAPAttribute("objectclass", objectclasses);
LDAPAttributeSet attrSet = new LDAPAttributeSet();
attrSet.add(attr1);
attrSet.add(attr2);</programlisting>
</sect2>
<sect2 id="add-new-entry"><title>Creating a New Entry</title>
<para>An entry contains a distinguished name (DN), which identifies the entry
in the directory, and a set of attributes. In the LDAP Java classes, an entry
is represented by an <classname>LDAPEntry</classname> object.</para>
<para>To create a new entry, use the <literal>LDAPEntry</literal> constructor.</para>
<programlisting>LDAPAttribute attr1 = new LDAPAttribute("cn", "Jane St. Clair");
String objectclasses[] = {"top", "person", "organizationalPerson",
"inetOrgPerson"};
LDAPAttribute attr2 = new LDAPAttribute("objectclass", objectclasses);
LDAPAttributeSet attrSet = new LDAPAttributeSet();
attrSet.add(attr1);
attrSet.add(attr2);
String dn = "uid=jsclair,ou=People,dc=example,dc=com";
LDAPEntry newEntry = new LDAPEntry(dn, attrs);</programlisting>
</sect2>
<sect2 id="add-entry-dir"><title>Adding the New Entry to the Directory</title>
<itemizedlist>
<para>Before you add an entry to the directory, make sure that you have done
the following:</para>
<listitem><para>You have specified the object classes of the entry using the <literal>
objectclass</literal> attribute, and have specified the required attributes
for those object classes.</para>
<itemizedlist>
<para>For example, organizational units might be represented by entries of
the <literal>organizationalUnit</literal> object class. To add an entry for
an organizational unit, you need to specify the following attributes in the
entry:</para>
<listitem><para><literal>objectclass</literal> with value <literal>top</literal></para>
</listitem>
<listitem><para><literal>objectclass</literal> with value <literal>organizationalUnit
</literal></para></listitem>
<listitem><para><literal>ou</literal> with the value for the organizational
unit, such as <literal>People</literal></para></listitem>
</itemizedlist>
</listitem>
<listitem><para>You have authenticated as a user who has the access permissions
to add the entry to the directory.</para><para>If you do not have permission
to add the entry, an <classname>LDAPException</classname> is returned with
result code <constant>LDAPException.INSUFFICIENT_ACCESS_RIGHTS</constant>.</para>
</listitem>
</itemizedlist>
<para>To add the entry to the directory, invoke the <literal>add</literal> method
of the <classname>LDAPConnection</classname> object.</para>
<programlisting>try {
LDAPConnection ld = new LDAPConnection();
ld.connect("localhost", LDAPv3.DEFAULT_PORT);
ld.authenticate(bindDNWithWriteAccess, bindPassword);
LDAPEntry newEntry = new LDAPEntry(dn, attrs);
ld.add(newEntry);
} catch (LDAPException e) {
System.err.println("Could not add " + dn + ":" + e.toString());
}</programlisting>
</sect2>
<sect2 id="add-entry-example"><title>Example of Adding an Entry</title>
<para>The following example adds a new entry to the directory for the user
who is named William Jensen.</para>
<programlisting>import netscape.ldap.*;
import java.util.*;
public class Add {
public static void main(String[] args) {
/* Specify the DN to add */
String dn = "uid=wbjensen, ou=People, dc=example,dc=com";
/* Specify the attributes of the entry */
String objectclass_values[] =
{"top", "person", "organizationalPerson", "inetOrgPerson"};
String cn_values[] =
{"William B Jensen", "William Jensen", "Bill Jensen"};
String sn_values[] = {"Jensen"};
String givenname_values[] = {"William", "Bill"};
String telephonenumber_values[] = {"+1 800 555 1212"};
LDAPAttributeSet attrs = new LDAPAttributeSet();
LDAPAttribute attr = new LDAPAttribute("objectclass");
for (int i = 0; i &lt; objectclass_values.length; i++) {
attr.addValue(objectclass_values[i]);
}
attrs.add(attr);
attr = new LDAPAttribute("cn");
for (int i = 0; i &lt; cn_values.length; i++) {
attr.addValue(cn_values[i]);
}
attrs.add(attr);
attr = new LDAPAttribute("sn");
for (int i = 0; i &lt; sn_values.length; i++) {
attr.addValue(sn_values[i]);
}
attrs.add(attr);
attr = new LDAPAttribute("givenname");
for (int i = 0; i &lt; givenname_values.length; i++) {
attr.addValue(givenname_values[i]);
}
attrs.add(attr);
attr = new LDAPAttribute("telephonenumber");
for (int i = 0; i &lt; telephonenumber_values.length; i++) {
attr.addValue(telephonenumber_values[i]);
}
attrs.add(attr);
attrs.add(new LDAPAttribute("uid", "wbjensen"));
/* Create an entry with this DN and these attributes */
LDAPEntry myEntry = new LDAPEntry(dn, attrs);
try {
/* Connect and authenticate as a user with write access. */
UserArgs userArgs = new UserArgs("Add", args, true);
LDAPConnection ld = new LDAPConnection();
ld.connect(userArgs.getHost(), userArgs.getPort());
ld.authenticate(userArgs.getBindDN(), userArgs.getPassword());
/* Now add the entry to the directory */
ld.add(myEntry);
System.out.println("Entry added");
ld.disconnect();
} catch(LDAPException e) {
if (e.getLDAPResultCode() ==
LDAPException.ENTRY_ALREADY_EXISTS) {
System.out.println("Error: Entry already present");
} else {
System.out.println("Error: " + e.toString());
}
}
}
}</programlisting>
</sect2>
</sect1>
<sect1 id="mod-entry"><title>Modifying an Entry With &DirectorySDKForJava;</title>
<indexterm>
<primary>modifying</primary>
<secondary>entries</secondary>
</indexterm><indexterm>
<primary>entries</primary>
<secondary>modifying</secondary>
</indexterm><indexterm>
<primary>attributes</primary>
<secondary>modifying</secondary>
</indexterm>
<orderedlist>
<para>To modify an entry in the directory, follow this general procedure:</para>
<listitem><para>Specify each attribute change to make.</para>
<itemizedlist>
<listitem><para>If you are making only one change to the entry, construct
an <classname>LDAPModification</classname> object that specifies the change
that needs to be made.</para></listitem>
<listitem><para>If you are making more than one change, you need to construct
an <classname>LDAPModificationSet</classname> object that specifies the changes
that need to be made.</para></listitem>
</itemizedlist>
</listitem>
<listitem><para>Use the DN of the entry to find and update the
entry in the directory.</para></listitem></orderedlist>
<sect2 id="mod-entry-spec-changes"><title>Specifying Attribute Changes</title>
<para>You can add new values to an attribute, remove existing attribute values,
or change the values of an existing attribute. You can also remove an attribute
by removing all values for the attribute or by not providing values for the
attribute.</para>
<sect3 id="mod-entry-new-values"><title>Adding New Attribute Values</title>
<indexterm>
<primary>attributes</primary>
<secondary>adding values to</secondary>
</indexterm><indexterm>
<primary>adding</primary>
<secondary>values to an attribute</secondary>
</indexterm>
<itemizedlist>
<para>To add new values to an attribute in an entry, construct a new <classname>LDAPAttribute
</classname> object. Specify the name of the attribute. Also, specify the
values to add. Then, perform one of the following operations:</para>
<listitem><para>If you are making a single change to the entry, construct
a new <classname>LDAPModification</classname> object to specify that change.
Pass <constant>LDAPModification.ADD</constant> and the <classname>LDAPAttribute</classname> object
as arguments to the <literal>LDAPModification</literal> constructor.</para>
</listitem>
<listitem><para>If you are collecting multiple changes to an entry in an <classname>
LDAPModificationSet</classname> object, invoke the <literal>add</literal> method.
This method adds the change to the set of modifications. Pass <constant>LDAPModification.ADD
</constant> and the <classname>LDAPAttribute</classname> object as arguments
to this method.</para></listitem>
</itemizedlist>
<para>For example, the following code excerpt adds the value <literal>babs@example.com
</literal> to the <literal>mail</literal> attribute:</para>
<programlisting>LDAPModificationSet mods = new LDAPModificationSet();
LDAPAttribute attrMail = new LDAPAttribute("mail", "babs@example.com");
mods.add(LDAPModification.ADD, attrMail);</programlisting>
<para>If the specified attribute does not exist in the entry, the attribute
is created for the entry.</para></sect3>
<sect3 id="mod-entry-del-values"><title>Deleting Attribute Values</title>
<indexterm>
<primary>attributes</primary>
<secondary>removing values from</secondary>
</indexterm><indexterm>
<primary>deleting</primary>
<secondary>values from an attribute</secondary>
</indexterm><indexterm>
<primary>removing</primary>
<secondary>values from an attribute</secondary>
</indexterm>
<itemizedlist>
<para>To remove values from an attribute in an entry, construct a new <classname>
LDAPAttribute</classname> object, specifying the name of the attribute and
the values to remove. Then, perform one of the following operations:</para>
<listitem><para>If you are making a single change to the entry, construct
a new <classname>LDAPModification</classname> object to specify that change.
Pass <constant>LDAPModification.DELETE</constant> and the <classname>LDAPAttribute
</classname> object as arguments to the <literal>LDAPModification</literal> constructor.
</para></listitem>
<listitem><para>If you are collecting multiple changes to an entry in an <classname>
LDAPModificationSet</classname> object, invoke the <literal>add</literal> method.
The method adds the change to the set of modifications. Pass <constant>LDAPModification.DELETE
</constant> and the <classname>LDAPAttribute</classname> object as arguments
to this method.</para></listitem>
</itemizedlist>
<para>For example, the following code excerpt removes the value <literal>babs@example.com
</literal> from the <literal>mail</literal> attribute:</para>
<programlisting>LDAPModificationSet mods = new LDAPModificationSet();
LDAPAttribute attrMail = new LDAPAttribute("mail", "babs@example.com");
mods.add(LDAPModification.DELETE, attrMail);</programlisting>
<para>If you remove all values from an attribute, the attribute is removed
from the entry. If you do not specify any values in the <classname>LDAPAttribute</classname> object,
the attribute is also removed from the entry.</para></sect3>
<sect3 id="mod-entry-replace-values"><title>Replacing Attribute Values</title>
<indexterm>
<primary>attributes</primary>
<secondary>replacing values of</secondary>
</indexterm><indexterm>
<primary>changing</primary>
<secondary>values of an attribute</secondary>
</indexterm><indexterm>
<primary>modifying</primary>
<secondary>values of an attribute</secondary>
</indexterm><indexterm>
<primary>replacing</primary>
<secondary>values of an attribute</secondary>
</indexterm>
<itemizedlist>
<para>To replace values for an attribute in an entry, construct a new <classname>
LDAPAttribute</classname> object, specifying the name of the attribute and
the values to replace. Then, perform one of the following operations:</para>
<listitem><para>If you are making a single change to the entry, construct
a new <classname>LDAPModification</classname> object to specify that change.
Pass <constant>LDAPModification.REPLACE</constant> and the <classname>LDAPAttribute
</classname> object as arguments to the <literal>LDAPModification</literal> constructor.
</para></listitem>
<listitem><para>If you are collecting multiple changes to an entry in an <classname>
LDAPModificationSet</classname> object, invoke the <literal>add</literal> method.
The method adds the change to the set of modifications. Pass <constant>LDAPModification.REPLACE
</constant> and the <classname>LDAPAttribute</classname> object as arguments
to this method.</para></listitem>
</itemizedlist>
<para>For example, the following code excerpt replaces the existing value
of the <literal>mail</literal> attribute with <literal>babs@example.com</literal>:
</para>
<programlisting>LDAPModificationSet mods = new LDAPModificationSet();
LDAPAttribute attrMail = new LDAPAttribute("mail", "babs@example.com");
mods.add(LDAPModification.REPLACE, attrMail);</programlisting>
<para>If the specified attribute does not exist in the entry, the attribute
is created for the entry. If you do not specify any values in the <classname>LDAPAttribute
</classname> object, the attribute is removed from the entry.</para></sect3>
<sect3 id="mode-entry-del-attr"><title>Removing an Attribute</title>
<indexterm>
<primary>attributes</primary>
<secondary>removing from an entry</secondary>
</indexterm><indexterm>
<primary>entries</primary>
<secondary>removing attributes from</secondary>
</indexterm>
<itemizedlist>
<para>To remove an attribute from an entry, perform one of the following operations:
</para>
<listitem><para>Replace the values of the attribute with an <classname>LDAPAttribute
</classname> object that contains no values.</para></listitem>
<listitem><para>Remove the values of the attribute with an <classname>LDAPAttribute
</classname> object that contains no values.</para></listitem>
<listitem><para>Remove all values for the attribute.</para></listitem>
</itemizedlist>
<para>For example, the following code excerpt demonstrates the first two options
by preparing an <classname>LDAPModificationSet</classname> object to remove
the <literal>mail</literal> and <literal>description</literal> attributes:</para>
<programlisting>LDAPModificationSet mods = new LDAPModificationSet();
LDAPAttribute attrMail = new LDAPAttribute("mail");
LDAPAttribute attrDesc = new LDAPAttribute("description");
mods.add(LDAPModification.REPLACE, attrMail);
mods.add(LDAPModification.DELETE, attrDesc);</programlisting>
</sect3>
</sect2>
<sect2 id="mod-entry-dir"><title>Modifying the Entry in the Directory</title>
<itemizedlist>
<para>Before you modify an entry, make sure of the following:</para>
<listitem><para>You have not removed any of the required attributes for that
object class.</para></listitem>
<listitem><para>You have authenticated as a user who has the access permissions
to modify the entry in the directory.</para><para>If you do not have permission
to modify the entry, an <classname>LDAPException</classname> is returned with
the result code <constant>LDAPException.INSUFFICIENT_ACCESS_RIGHTS</constant>.</para>
</listitem>
</itemizedlist>
<para>You specify the change with an <classname>LDAPModification</classname> object.
You specify a list of changes with an <classname>LDAPModificationSet</classname> object.
When finished specifying the change, pass the object with the DN of the entry
to the <literal>modify</literal> method of the <classname>LDAPConnection</classname> object.
</para></sect2>
<sect2 id="mod-entry-example"><title>Example of Modifying an Entry</title>
<para>The following example modifies an entry in the directory.</para>
<programlisting>import netscape.ldap.*;
import java.util.*;
public class ModAttrs {
public static void main(String[] args) {
String ENTRYDN = "uid=bjensen, ou=People, dc=example,dc=com";
LDAPModificationSet mods = new LDAPModificationSet();
LDAPAttribute attrEmail =
new LDAPAttribute("mail", "babs@example.com");
mods.add(LDAPModification.REPLACE, attrEmail);
LDAPAttribute attrDesc = new LDAPAttribute("description",
"This entry was modified with the ModAttrs program");
mods.add(LDAPModification.ADD, attrDesc);
try {
/* Connect and authenticate as a user with write access. */
UserArgs userArgs = new UserArgs("ModAttrs", args, true);
LDAPConnection ld = new LDAPConnection();
ld.connect(userArgs.getHost(), userArgs.getPort());
ld.authenticate(userArgs.getBindDN(), userArgs.getPassword());
/* Now modify the entry in the directory */
ld.modify(ENTRYDN, mods);
System.out.println("Entry modified" );
ld.disconnect();
} catch(LDAPException e) {
if (e.getLDAPResultCode() == LDAPException.NO_SUCH_OBJECT) {
System.out.println("Error: No such entry");
} else if (e.getLDAPResultCode() ==
LDAPException.INSUFFICIENT_ACCESS_RIGHTS) {
System.out.println("Error: Insufficient rights");
} else if (e.getLDAPResultCode() ==
LDAPException.ATTRIBUTE_OR_VALUE_EXISTS) {
System.out.println("Error: Attribute or value exists");
} else {
System.out.println("Error: " + e.toString());
}
}
}
}</programlisting>
</sect2>
</sect1>
<sect1 id="del-entry"><title>Deleting an Entry With &DirectorySDKForJava;</title>
<indexterm>
<primary>deleting an entry</primary>
</indexterm><indexterm>
<primary>entries</primary>
<secondary>deleting</secondary>
</indexterm>
<para>Before you delete an entry, authenticate as a user who has the access
permissions to remove the entry from the directory. If you do not have permission
to delete the entry, an <classname>LDAPException</classname> is returned with
result code <constant>LDAPException.INSUFFICIENT_ACCESS_RIGHTS</constant>.</para>
<para>To remove an entry from the directory, invoke the <literal>delete</literal> method
of the <classname>LDAPConnection</classname> object. Specify the DN of the
entry that you want to remove.</para>
<para>The following example deletes the entry that is added in <olink type="auto-generated" targetptr="add-entry-example">Example of Adding an Entry</olink>.
</para>
<programlisting>import netscape.ldap.*;
import java.util.*;
public class Del {
public static void main(String[] args) {
try {
/* Connect and authenticate as a user with write access. */
UserArgs userArgs = new UserArgs("Del", args, true);
LDAPConnection ld = new LDAPConnection();
ld.connect(userArgs.getHost(), userArgs.getPort());
ld.authenticate(userArgs.getBindDN(), userArgs.getPassword());
/* Specify the DN we're deleting */
String dn = "uid=wbjensen, ou=People, dc=example,dc=com";
ld.delete(dn);
System.out.println("Entry deleted");
ld.disconnect();
} catch(LDAPException e) {
if (e.getLDAPResultCode() == LDAPException.NO_SUCH_OBJECT) {
System.out.println("Error: No such entry");
} else if (e.getLDAPResultCode() ==
LDAPException.INSUFFICIENT_ACCESS_RIGHTS) {
System.out.println("Error: Insufficient rights");
} else {
System.out.println("Error: " + e.toString());
}
}
}
}</programlisting>
</sect1>
<sect1 id="rename-entry"><title>Renaming an Entry With &DirectorySDKForJava;</title>
<indexterm>
<primary>changing the name of an entry</primary>
</indexterm><indexterm>
<primary>moving an entry</primary>
</indexterm><indexterm>
<primary>renaming an entry</primary>
</indexterm><indexterm>
<primary>entries</primary>
<secondary>renaming</secondary>
</indexterm>
<para>Before you rename an entry, authenticate as a user who has the access
permissions to perform the operation. If you do not have permission to rename
the entry, an <classname>LDAPException</classname> is returned with result
code <constant>LDAPException.INSUFFICIENT_ACCESS_RIGHTS</constant>.</para>
<itemizedlist>
<para>To rename an entry, invoke the <literal>rename</literal> method of the <classname>
LDAPConnection</classname> object. With this method, you can change the following:
</para>
<listitem><para>The relative distinguished name (RDN) of the entry</para>
</listitem>
<listitem><para>The location of the entry in the directory by changing the
DN and not just the RDN</para><para>Some LDAP servers do not support moving
entries by changing their DNs. Check your LDAP server documentation for further
information.</para></listitem>
</itemizedlist>
<sect2 id="rename-entry-newrdn"><title>Changing the Relative Distinguished
Name</title>
<para>When invoking the <literal>rename</literal> method of the <classname>LDAPConnection
</classname> object, you can specify a <parameter>deleteoldrdn</parameter> parameter.
The parameter allows you to remove the old RDN from the entry. Suppose an
entry has the following values for the <literal>uid</literal> attribute:</para>
<programlisting>uid: wbjensen
uid: wbj</programlisting>
<para>The following code excerpt changes the user ID value <literal>wbjensen</literal> to <literal>
wjensen</literal> and removes the <literal>wbjensen</literal> value:</para>
<programlisting>ld.rename("uid=wbjensen,ou=People,dc=example,dc=com", "uid=wjensen", true);
</programlisting>
<para>The resulting values in the entry do not include the old RDN:</para>
<programlisting>uid: wbjensen
uid: wbj</programlisting>
<para>The following code excerpt retains the existing user ID value after
the rename operation:</para>
<programlisting>ld.rename("uid=wbjensen,ou=People,dc=example,dc=com", "uid=wjensen", false);
</programlisting>
<para>In this case, the resulting values in the entry <emphasis>do</emphasis> include
the old RDN:</para>
<programlisting>uid: wbjensen
uid: wjensen
uid: wbj</programlisting>
<para>The DN after the rename operation is, however, <literal>uid=wjensen,ou=People,dc=example,dc=com
</literal>.</para>
<para>The following example creates an entry and then renames it:</para>
<programlisting>import netscape.ldap.*;
import java.util.*;
public class ModRdn {
public static void main(String[] args) {
/* Values for creating the entry */
String objectclass_values[] =
{"top", "person", "organizationalPerson", "inetOrgPerson"};
String cn_values[] = {"Jacques Smith"};
String sn_values[] = {"Smith"};
String givenname_values[] = {"Jacques"};
/* Specify the DN to add */
String base = "ou=People, dc=example,dc=com";
String dn = "uid=jsmith" + "," + base;
String nrdn = "uid=jmsmith"; // The new RDN
String ndn = nrdn + "," + base; // The target DN
/* Create an attribute set with all desired attributes */
LDAPAttributeSet attrs = new LDAPAttributeSet();
LDAPAttribute attr =
new LDAPAttribute("objectclass", objectclass_values);
attrs.add(attr);
attr = new LDAPAttribute("cn", cn_values);
attrs.add(attr);
attr = new LDAPAttribute("sn", sn_values);
attrs.add(attr);
attr = new LDAPAttribute("givenname", givenname_values);
attrs.add(attr);
attrs.add(new LDAPAttribute("uid", nrdn));
/* Create an entry with this DN and these attributes */
LDAPEntry myEntry = new LDAPEntry(dn, attrs);
try {
/* Connect and authenticate as a user with write access. */
UserArgs userArgs = new UserArgs("ModRdn", args, true);
LDAPConnection ld = new LDAPConnection();
ld.connect(userArgs.getHost(), userArgs.getPort());
ld.authenticate(userArgs.getBindDN(), userArgs.getPassword());
/* Add the entry */
try {
ld.add(myEntry);
} catch(LDAPException e) {
/* If entry exists already, fine. Ignore this error. */
if (e.getLDAPResultCode() !=
LDAPException.ENTRY_ALREADY_EXISTS) throw e;
}
/* Delete the destination entry, for this example */
try {
ld.delete(ndn);
}
catch(LDAPException e) {
/* If entry does not exist, fine. Ignore this error. */
if (e.getLDAPResultCode() != LDAPException.NO_SUCH_OBJECT)
throw e;
}
/* Do the modrdn operation */
ld.rename(dn, nrdn, false);
System.out.println("The modrdn operation was successful. ");
System.out.println(
"Entry " + dn + " has been changed to " + ndn);
ld.disconnect();
}
catch(LDAPException e) {
if (e.getLDAPResultCode() == LDAPException.NO_SUCH_OBJECT) {
System.out.println("Error: No such entry");
} else if (e.getLDAPResultCode() ==
LDAPException.INSUFFICIENT_ACCESS_RIGHTS) {
System.out.println("Error: Insufficient rights");
} else if (e.getLDAPResultCode() ==
LDAPException.ATTRIBUTE_OR_VALUE_EXISTS) {
System.out.println("Error: Attribute or value exists");
} else {
System.out.println("Error: " + e.toString());
}
}
}
}</programlisting>
</sect2>
<sect2 id="rename-entry-newdn"><title>Changing the Distinguished Name</title>
<para>When invoking the <literal>rename</literal> method of the <classname>LDAPConnection
</classname> object, you can specify a <parameter>newParentDN</parameter> parameter.
The parameter allows you to move the entry from one part of the directory
to another part by changing its DN. You can use the parameter even if the
RDN does not change.</para>
<para>The following example moves Sam Carter's entry from the organizational
unit People, to the organizational unit Special Users:</para>
<programlisting>import netscape.ldap.*;
import java.util.*;
public class ModDn {
public static void main(String[] args) {
try {
/* Connect and authenticate as a user with write access. */
UserArgs userArgs = new UserArgs("ModDn", args, true);
LDAPConnection ld = new LDAPConnection();
ld.connect(userArgs.getHost(), userArgs.getPort());
ld.authenticate(3, userArgs.getBindDN(),userArgs.getPassword());
/* Elevate Sam Carter from mere person to Special User. */
String rdn = "uid=scarter";
String oldParent = "ou=people,dc=example,dc=com";
String newParent = "ou=special users,dc=example,dc=com";
String dn = rdn + "," + oldParent;
String ndn = rdn + "," + newParent;
/* Read Sam's entry to make sure it exists before moving it. */
try {
LDAPEntry le = ld.read(dn);
}
catch(LDAPException e) {
System.err.println(
"Cannot read " + dn + ": " + e.toString());
throw e;
}
/* Delete the moved entry if it already exists. */
try {
ld.delete(ndn);
}
catch(LDAPException e) {
/* Ignore notification that the new entry is not there. */
if (e.getLDAPResultCode() != e.NO_SUCH_OBJECT) throw e;
}
/* Move Sam's entry. */
ld.rename(dn, rdn, newParent, false);
System.out.println("Entry " + dn + " has moved to " + ndn);
ld.disconnect();
}
catch(LDAPException e) {
System.err.println("Error: " + e.toString());
}
}
}</programlisting>
</sect2>
</sect1>
</chapter>

View File

@@ -0,0 +1,277 @@
<!--
Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
Portions copyright 1999 Netscape Communications Corporation. All
Rights Reserved.
The contents of this document are subject to the terms of the
Creative Commons Attribution-ShareAlike 2.5 license or any later
version (the "License"). You may not use this document except in
compliance with the License.
See the License for the specific language governing
permissions and limitations under the License. You can obtain
a copy of the License at
http://creativecommons.org/licenses/by-sa/2.5/legalcode.
-->
<chapter id="asynchronous"><title>Writing Asynchronous Clients With &DirectorySDKForJava;</title>
<highlights>
<para>This chapter shows how to use the asynchronous interface to LDAP in
Java applications.</para>
<itemizedlist>
<para>This chapter covers the following topics:</para>
<listitem><para><olink targetptr="async-vs-sync">Synchronous and Asynchronous Connections With Directory SDK for Java</olink></para></listitem>
<listitem><para><olink targetptr="async-using">Common Uses for the Asynchronous Interface With Directory SDK for Java</olink></para></listitem>
<listitem><para><olink targetptr="async-new">Classes in the Asynchronous Interface for Directory SDK for Java</olink></para></listitem>
<listitem><para><olink targetptr="async-search">Performing Asynchronous Searches With Directory SDK for Java</olink></para>
</listitem>
<listitem><para><olink targetptr="async-further">Further Reading About the Asynchronous Interface for Directory SDK for Java</olink></para></listitem>
</itemizedlist>
</highlights>
<sect1 id="async-vs-sync"><title>Synchronous and Asynchronous Connections
With Directory SDK for Java</title>
<indexterm>
<primary>asynchronous interface</primary>
<secondary>explained</secondary>
</indexterm><indexterm>
<primary>synchronous interface</primary>
<secondary>explained</secondary>
</indexterm>
<para>Most operations with &DirectorySDKForJava; are performed synchronously.
A connection is established, a request is sent, the results are returned.
Then the application resumes. Though the &DirectorySDKForJava; can deliver
one search result at a time, other operations block until completion when
accessing an LDAP server.</para>
<para>Sometimes, initiating a new request while another request executes can
be useful. An additional interface is provided to access the built-in support
in &DirectorySDKForJava; for these asynchronous requests. By returning
control to an application before obtaining a response, the asynchronous interface
allows you to perform complex operations requiring access to low-level LDAP
mechanisms.</para>
<para><classname>LDAPConnection</classname> methods support both asynchronous
requests and synchronous requests. Synchronous methods wait for response messages
from a server and then process the responses for you. Asynchronous methods
require that you check for the messages. You then perform the processing in
your code. This mechanism allows you to make additional LDAP requests while
waiting for results to return.</para></sect1>
<sect1 id="async-using"><title>Common Uses for the Asynchronous Interface
With Directory SDK for Java</title>
<indexterm>
<primary>asynchronous interface</primary>
<secondary>common uses</secondary>
</indexterm>
<para>Since using the asynchronous interface involves managing more complex
code in an application, use the asynchronous methods only when required. The
most common use is for merging the results of searches that involve multiple
servers or that are executed simultaneously on different subtrees. This method
is sometimes referred to as <firstterm>multiplexing</firstterm>.</para>
<para>A search that multiplexes servers can make a request to an array of
hosts. A search that multiplexes query statements can make different requests
to different subtrees of a server. If you combine these search methods, you
can perform complex searches across a number of servers without having to
wait for individual responses.</para>
<para>The following example illustrates a practical use of multiplexed searches
and the asynchronous interface.</para>
<para>Suppose event notification must be implemented as a generic service
with LDAP persistent search. Synchronous methods require a new thread for
every request to the service. This solution is not scalable and can exhaust
system resources very quickly.</para>
<para>After the search is rewritten using the asynchronous interface, performance
improves dramatically. Since asynchronous searches do not block until completion,
the persistent search results can be multiplexed into one queue and then processed
on a single thread.</para></sect1>
<sect1 id="async-new"><title>Classes in the Asynchronous Interface for Directory
SDK for Java</title>
<indexterm>
<primary>asynchronous interface</primary>
<secondary>classes</secondary>
</indexterm>
<para>&DirectorySDKForJava; handles asynchronous communication through
the <classname>LDAPAsynchronousConnection</classname> interface and its dependent
classes. These files collectively form the asynchronous extensions to the
LDAP API.</para>
<para><classname>LDAPAsynchronousConnection</classname> defines methods for
authenticating to a server, as well as for searching, modifying, comparing,
and deleting entries in the directory.</para>
<para>When you call a method of <classname>LDAPAsynchronousConnection</classname>,
the method returns a listener object. This object acts as a message queue.
The object accepts search results and server-generated responses to LDAP requests.
The LDAP client has the responsibility to read and process these messages.</para>
<itemizedlist>
<para><classname>LDAPAsynchronousConnection</classname> incorporates the following
classes for handling asynchronous client-server interactions:</para>
<listitem><para><classname>LDAPMessage</classname>, which is the base class
for LDAP request and response messages.</para></listitem>
<listitem><para><classname>LDAPResponse</classname>, which extends <classname>LDAPMessage
</classname>, represents a message received from an LDAP server in response
to a request.</para></listitem>
<listitem><para><classname>LDAPExtendedResponse</classname>, which extends <classname>
LDAPResponse</classname>. This response is the response that an LDAP server
returns when handling an extended operation request.</para></listitem>
<listitem><para><classname>LDAPResponseListener</classname> queues <classname>LDAPResponse
</classname> messages.</para></listitem>
<listitem><para><classname>LDAPSearchResult</classname>, which extends <classname>
LDAPMessage</classname>. The response contains a single LDAP entry. The response
is one of the responses an LDAP server can return when handling a search request.
</para></listitem>
<listitem><para><classname>LDAPSearchResultReference</classname>, which extends <classname>
LDAPMessage</classname>. The response contains a referral. The response is
one of the responses that an LDAP server can return when handling a search
request.</para></listitem>
<listitem><para><classname>LDAPSearchListener</classname> queues search results
and references.</para></listitem>
</itemizedlist>
</sect1>
<sect1 id="async-search"><title>Performing Asynchronous Searches With Directory
SDK for Java</title>
<para>One of the most common uses of the asynchronous interface is for performing
multiplexed searches using more than one server or suffix.</para>
<task id="async-search-mult-servers"><title>To Search Across Multiple Servers</title>
<indexterm>
<primary>asynchronous interface</primary>
<secondary>search multiple servers</secondary>
</indexterm>
<tasksummary>
<para>To search on more than one server, perform the following steps.</para>
</tasksummary>
<procedure>
<step><para>Connect to all the servers.</para></step>
<step><para>Create a response listener for one search.</para></step>
<step><para>Share the response listener with all the other searches.</para>
</step>
<step><para>Obtain and process the results.</para></step>
<step><para>Disconnect from the servers.</para></step>
</procedure>
<example id="async-search-mult-servers-example">
<title>Searching Across Multiple Servers</title>
<para>This example demonstrates how to search on two servers at the same time.</para>
<programlisting>import netscape.ldap.*;
import java.util.*;
public class MultiplexServers {
public static void main(String[] args) {
try {
LDAPConnection[] ld = new LDAPConnection[2];
String[] hosts = {"server1", "server2"};
int[] ports = {389, 389};
String[] bases = {"dc=example,dc=com", "dc=example,dc=com"};
/* search for all entries with surname of Jensen */
String MY_FILTER = "(sn=Jensen)";
for (int i = 0; i &lt; ld.length; i++) {
ld[i] = new LDAPConnection();
ld[i].connect(hosts[i], ports[i]);
}
/* Get a response listener for one search */
LDAPSearchListener l = ld[0].search(bases[0], ld[0].SCOPE_SUB,
MY_FILTER, null, false, (LDAPSearchListener)null);
/* Share the listener */
for (int i = 1; i &lt; ld.length; i++) {
ld[i].search(bases[i], ld[i].SCOPE_SUB,
MY_FILTER, null, false, l);
}
/* Loop on results until finished */
LDAPMessage msg;
while ((msg = l.getResponse()) != null) {
if (msg instanceof LDAPSearchResultReference) {
; // Ignore referrals
} else if (msg instanceof LDAPSearchResult) {
LDAPEntry entry = ((LDAPSearchResult)msg).getEntry();
System.out.println("Found entry: " + entry.getDN());
} else if (msg instanceof LDAPResponse) {
int result = ((LDAPResponse)msg).getResultCode();
if (result != 0) {
System.out.println("Result code: " + result);
System.out.println("Error message: " +
((LDAPResponse)msg).getErrorMessage());
}
}
}
for (int i = 0; i &lt; ld.length; i++) {
ld[i].disconnect();
}
} catch (LDAPException e) {
System.err.println(e.toString());
}
}
}</programlisting>
</example>
</task>
<task id="async-search-mult-suffixes"><title>To Search Across Multiple Suffixes
on a Single Server</title>
<indexterm>
<primary>asynchronous interface</primary>
<secondary>search multiple suffixes</secondary>
</indexterm>
<tasksummary>
<para>To search on more than one suffix, perform the following steps.</para>
</tasksummary>
<procedure>
<step><para>Connect to the server.</para></step>
<step><para>Create a response listener for one search.</para></step>
<step><para>Share (multiplex) the response listener with the other searches.</para>
</step>
<step><para>Obtain and process the results.</para></step>
<step><para>Disconnect from the server.</para></step>
</procedure>
<example id="async-search-mult-suffixes-example">
<title>Searching Across Multiple Suffixes</title>
<para>This example demonstrates how to search across two suffixes at the same
time.</para>
<programlisting>import netscape.ldap.*;
import java.util.*;
public class MultiplexSuffixes {
public static void main(String[] args) {
try {
UserArgs userArgs =
new UserArgs("MultipleSuffixes", args, false);
LDAPConnection ld = new LDAPConnection();
ld.connect(userArgs.getHost(), userArgs.getPort());
String[] bases = {"dc=example,dc=com",
"ou=groups,dc=example,dc=com"};
String MY_FILTER = "(objectclass=*)";
/* Get a response listener for one search */
LDAPSearchListener l = ld.search(bases[0], ld.SCOPE_ONE,
MY_FILTER, null, false, (LDAPSearchListener)null);
/* Share the listener */
for (int i = 1; i &lt; bases.length; i++) {
ld.search(bases[i], ld.SCOPE_ONE,
MY_FILTER, null, false, l);
}
/* Loop on results until finished */
LDAPMessage msg;
while ((msg = l.getResponse()) != null) {
if (msg instanceof LDAPSearchResultReference) {
; // Ignore referrals
} else if (msg instanceof LDAPSearchResult) {
LDAPEntry entry = ((LDAPSearchResult)msg).getEntry();
System.out.println("Found entry: " + entry.getDN());
} else if (msg instanceof LDAPResponse) {
int result = ((LDAPResponse)msg).getResultCode();
if (result != 0) {
System.out.println("Result code: " + result);
System.out.println("Error message: " +
((LDAPResponse)msg).getErrorMessage());
}
}
}
ld.disconnect();
} catch (LDAPException e) {
System.err.println(e.toString());
}
}
}</programlisting>
</example>
</task>
</sect1>
<sect1 id="async-further"><title>Further Reading About the Asynchronous Interface
for Directory SDK for Java</title>
<para>The asynchronous interface is defined in an Internet Draft, <citetitle>The
Java LDAP Application Programming Interface</citetitle>.</para></sect1>
</chapter>

View File

@@ -0,0 +1,617 @@
<!--
Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
Portions copyright 1999 Netscape Communications Corporation. All
Rights Reserved.
The contents of this document are subject to the terms of the
Creative Commons Attribution-ShareAlike 2.5 license or any later
version (the "License"). You may not use this document except in
compliance with the License.
See the License for the specific language governing
permissions and limitations under the License. You can obtain
a copy of the License at
http://creativecommons.org/licenses/by-sa/2.5/legalcode.
-->
<chapter id="common-classes"><title>Using the LDAP Java Classes</title>
<highlights>
<para>This chapter covers general LDAP Java classes that are commonly used
when writing LDAP clients.</para>
<itemizedlist>
<para>This chapter covers the following topics:</para>
<listitem><para><olink targetptr="jdk-info">Getting Information About Directory
SDK for Java</olink></para></listitem>
<listitem><para><olink targetptr="handling-exceptions">Handling Exceptions
With Directory SDK for Java</olink></para></listitem>
<listitem><para><olink targetptr="handling-referrals">Handling Referrals With
Directory SDK for Java</olink></para></listitem>
<listitem><para><olink targetptr="in-memory-cache">Using In-Memory Cache With
Directory SDK for Java</olink></para></listitem>
<listitem><para><olink targetptr="cloning-connection">Cloning a Connection
With Directory SDK for Java</olink></para></listitem>
<listitem><para><olink targetptr="handling-dns">Manipulating Distinguished
Names With Directory SDK for Java</olink></para></listitem>
</itemizedlist>
</highlights>
<sect1 id="jdk-info"><title>Getting Information About &DirectorySDKForJava;</title>
<indexterm>
<primary>&DirectorySDKForJava;</primary>
<secondary>getting information about</secondary>
</indexterm>
<para>You can get information about the version of &DirectorySDKForJava; that
you are using. Version information tells you the version of the LDAP Java
classes. Version information can also tell you the highest version of the
LDAP protocol that &DirectorySDKForJava; supports.</para>
<para>To get this information, use the <literal>getProperty</literal> method
of the <classname>LDAPConnection</classname> object.</para>
<programlisting>LDAPConnection ld = new LDAPConnection();
try {
&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("LDAP Java Classes Version: " +
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(Float) ld.getProperty(LDAPConnection.LDAP_PROPERTY_SDK));
&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("Highest version of LDAP supported: " +
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(Float) ld.getProperty(LDAPConnection.LDAP_PROPERTY_PROTOCOL));
&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("Authentication methods supported: " +
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(String) ld.getProperty(LDAPConnection.LDAP_PROPERTY_SECURITY));
} catch (LDAPException e) {
&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("Could not get SDK properties.");
&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("Error: " + e.toString());
}</programlisting>
<para>Although a <literal>setProperty</literal> method is provided, currently
no properties exist that you can set. If you invoke the <literal>setProperty</literal> method,
the method returns an <classname>LDAPException</classname>.</para></sect1>
<sect1 id="handling-exceptions"><title>Handling Exceptions With &DirectorySDKForJava;</title>
<indexterm>
<primary>exceptions</primary>
<secondary>handling</secondary>
</indexterm>
<para>In LDAP, the success or failure of an operation is specified by an LDAP
result code sent back to the client. For example, the result code <returnvalue>0</returnvalue> indicates
that the operation was successful. A non zero result code usually indicates
that an error occurred.</para>
<sect2 id="getting-info"><title>Getting Information About the Error</title>
<indexterm>
<primary>exceptions</primary>
<secondary>getting information about</secondary>
</indexterm><indexterm>
<primary>LDAP result code</primary>
</indexterm>
<para>In the LDAP Java classes, when an error occurs, an <classname>LDAPException
</classname> is returned. Referrals cause an <classname>LDAPReferralException</classname> to
be returned as described in <olink targetptr="handling-referrals">Handling
Referrals With Directory SDK for Java</olink>.</para>
<itemizedlist>
<para>An <classname>LDAPException</classname> contains the following information:
</para>
<listitem><para>The LDAP result code for the error that occurred</para>
</listitem>
<listitem><para>A message that contains any additional information about the
error from the server</para></listitem>
</itemizedlist>
<para>An error can occur when an entry specified by a DN cannot be found.
The <classname>LDAPException</classname> then also contains the DN of the <firstterm>
closest matching entry</firstterm> that can be found.</para>
<itemizedlist>
<para>To get information from the <classname>LDAPException</classname>, use
one of the following methods:</para>
<listitem><para>To get the string representation of the exception, use the <literal>
toString</literal> method.</para></listitem>
<listitem><para>To get the LDAP result code, use the <literal>getLDAPResultCode</literal> method.
</para></listitem>
<listitem><para>To get any additional information sent by the server, use
the <literal>getLDAPErrorMessage</literal> method.</para></listitem>
<listitem><para>To get the closest matching DN in cases where your client
specified a DN to a nonexistent entry, use the <literal>getMatchedDN</literal> method.
</para></listitem>
</itemizedlist>
<para>To get the error message describing the LDAP result code, use the <literal>
errorCodeToString</literal> method, as described in <olink
targetptr="error-message">Getting the Error Message</olink>.</para>
<para>The following section of code gets and prints information about an <classname>
LDAPException</classname>.</para>
<programlisting>try {
&nbsp;&nbsp;&nbsp;&nbsp;/* Attempt to perform an LDAP operation here. */
} catch (LDAPException e) {
&nbsp;&nbsp;&nbsp;&nbsp;/* Get and print the result code and any other info. */
&nbsp;&nbsp;&nbsp;&nbsp;int resultCode = e.getLDAPResultCode();
&nbsp;&nbsp;&nbsp;&nbsp;String serverInfo = e.getLDAPErrorMessage();
&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("LDAP Result Code: " + resultCode);
&nbsp;&nbsp;&nbsp;&nbsp;if (serverInfo != null) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("Additional Info: " + serverInfo);
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;/*
&nbsp;&nbsp;&nbsp;&nbsp; * If the exception was returned because an entry was
* not found, print the DN of the closest entry found.
&nbsp;&nbsp;&nbsp;&nbsp; */
&nbsp;&nbsp;&nbsp;&nbsp;switch (resultCode) {
&nbsp;&nbsp;&nbsp;&nbsp;case LDAPException.NO_SUCH_OBJECT:
&nbsp;&nbsp;&nbsp;&nbsp;case LDAPException.ALIAS_PROBLEM:
&nbsp;&nbsp;&nbsp;&nbsp;case LDAPException.INVALID_DN_SYNTAX:
&nbsp;&nbsp;&nbsp;&nbsp;case LDAPException.ALIAS_DEREFERENCING_PROBLEM:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String matchedDN = e.getMatchedDN();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (matchedDN != null) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("Closest Entry: " + matchedDN);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;
&nbsp;&nbsp;&nbsp;&nbsp;default:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;
&nbsp;&nbsp;&nbsp;&nbsp;}
}</programlisting>
</sect2>
<sect2 id="error-message"><title>Getting the Error Message</title>
<indexterm>
<primary>LDAP result code</primary>
<secondary>string description for</secondary>
</indexterm>
<para>To get the error message for an LDAP result code, use the <literal>errorCodeToString
</literal> method.</para>
<programlisting>try {
&nbsp;&nbsp;&nbsp;&nbsp;/* Attempt to perform an LDAP operation here. */
} catch (LDAPException e) {
&nbsp;&nbsp;&nbsp;&nbsp;/* Get and print the error message. */
&nbsp;&nbsp;&nbsp;&nbsp;int resultCode = e.getLDAPResultCode();
&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("Error: " + e.errorCodeToString(resultCode));
}</programlisting>
<para>Error messages corresponding to each LDAP result code are located either
inside the <filename>ldapjdk.jar</filename> file or under another directory
in your <envar>CLASSPATH</envar>, in a properties file named <filename>netscape/ldap/errors/ErrorCodes.props
</filename> or <filename>netscape/ldap/errors/ErrorCodes_<replaceable>locale</replaceable>.props
</filename>. <replaceable>locale</replaceable> can be a two-letter version
of the locale, such as <literal>de</literal>, <literal>fr</literal>, or <literal>
ja</literal>, or it can be a full version of the locale, such as <literal>en_US</literal>.
</para>
<para>When you invoke the <literal>errorCodeToString</literal> method of an <classname>
LDAPException</classname>, the method retrieves the error message string for
the specified locale. If no locale is specified, the method retrieves the
default locale from the properties file. The <literal>errorCodeToString</literal> method
looks for locale-specific properties files in the following order, retrieving
the first property that is found:</para>
<programlisting>netscape/ldap/error/ErrorCodes_<replaceable>language</replaceable>_<replaceable>
country</replaceable>.props
netscape/ldap/error/ErrorCodes_<replaceable>language</replaceable>.props
netscape/ldap/error/ErrorCodes.props</programlisting>
</sect2>
</sect1>
<sect1 id="handling-referrals"><title>Handling Referrals With &DirectorySDKForJava;</title>
<indexterm>
<primary>referrals</primary>
</indexterm>
<para>An LDAP server can receive a request for a DN that is not under its
directory tree. The server can then refer clients to another LDAP server that
might contain that DN. The response is known as a <firstterm>referral</firstterm>.
This section explains how to set up your LDAP client to handle referrals automatically.
</para>
<sect2 id="understanding-referrals"><title>Understanding Referrals</title>
<itemizedlist>
<para>Suppose an LDAP server has a directory that starts under <literal>dc=example,dc=com
</literal>. Your client might send the server a request to modify the entry
with the DN <literal>uid=bjensen,ou=People,o=example.com</literal>. The entry
is not under <literal>dc=example,dc=com</literal>. One of the following can
occur.</para>
<listitem><para>If the server is not configured to send a referral, an <classname>
LDAPException</classname> is returned with the LDAP result code <constant>LDAPException.NO_SUCH_OBJECT
</constant>.</para></listitem>
<listitem><para>If the server is configured to refer you to another LDAP server,
the server sends a referral back to your client.</para>
<itemizedlist>
<para>Depending on how your LDAP client is configured, one of the following
can occur:</para>
<listitem><para>If your client handles referrals automatically, your client
connects to the LDAP server specified in the referral and requests to modify
the entry. The client binds anonymously to that server. To bind as a specific
user, refer to <olink targetptr="enabling-referrals">Enabling or Disabling
Referral Handling</olink>.</para></listitem>
<listitem><para>If your client does not handle referrals automatically, an <classname>
LDAPReferralException</classname> is returned. You can get the LDAP URL specified
in the referral by catching the exception, and then invoking the <literal>getURLs
</literal> method.</para></listitem>
</itemizedlist>
<para>By default, clients built with &DirectorySDKForJava; are configured
to follow referrals automatically.</para></listitem>
</itemizedlist>
<para>Another concept that is similar to a referral is a search reference.
A <firstterm>search reference</firstterm> is an entry with the object class <literal>
referral</literal>. The <literal>ref</literal> attribute of this object contains
an LDAP URL that points to another LDAP server.</para>
<para>When your client searches a subtree of the directory that contains search
references, the server returns a mix of matching entries and search references.
As you iterate through the enumeration of search results, you can encounter
a search reference although your client does not handle referrals automatically.
An <classname>LDAPReferralException</classname> is then returned.</para></sect2>
<sect2 id="enabling-referrals"><title>Enabling or Disabling Referral Handling</title>
<indexterm>
<primary>referrals</primary>
<secondary>handling automatically</secondary>
</indexterm>
<para>By default, clients built with &DirectorySDKForJava; automatically
follow referrals to other servers.</para>
<itemizedlist>
<para>To change the way your client handles referrals, use one of two methods.
Use the <literal>setOption</literal> method of the <classname>LDAPConnection</classname> object
to change the behavior for all LDAP operations. Alternatively, use the <literal>setReferrals
</literal> method of the <classname>LDAPConstraints</classname> object to
change the behavior for a specific search request.</para>
<listitem><para>To prevent the client from automatically following referrals,
pass <literal>LDAPv3.REFERRALS</literal> and <literal>false</literal> as arguments
to the <literal>setOption</literal> method. Alternatively, pass <literal>false</literal> as
the argument to the <literal>setReferrals</literal> method.</para></listitem>
<listitem><para>To enable the client to follow referrals automatically again,
pass <literal>LDAPv3.REFERRALS</literal> and <literal>true</literal> as arguments
to the <literal>setOption</literal> method. Alternatively, pass <literal>true</literal> as
the argument to the <literal>setReferrals</literal> method.</para></listitem>
</itemizedlist>
</sect2>
<sect2 id="limiting-referral-hops"><title>Limiting Referral Hops</title>
<indexterm>
<primary>referrals</primary>
<secondary>specifying maximum hops</secondary>
</indexterm>
<para>You can specify the maximum number of referral hops that should be followed
in a sequence of referrals. You can set the preference for the connection.
You can also set the maximum as a constraint for specific search operations.
The maximum is called the <firstterm>referral hop limit</firstterm>.</para>
<para>For example, suppose you set a limit of two referral hops. If LDAP server
A refers to server B, B to C, and C to D, your client is being referred three
times in a row. Your client does not follow the referral to LDAP server D
because this referral exceeds the referral hop limit.</para>
<para>If the referral hop limit is exceeded, an <classname>LDAPReferralException</classname> is
returned.</para>
<para>To set the referral hop limit, use either of two methods. Use the <literal>
LDAPv3.REFERRALS_HOP_LIMIT</literal> preference with the <literal>setOption</literal> method
of the <classname>LDAPConnection</classname> object to change the behavior
for all LDAP operations. Alternatively, use the <literal>setHopLimit</literal> method
of the <classname>LDAPConstraints</classname> object to change the behavior
for a specific search request.</para>
<para>By default, the maximum number of referral hops is 10.</para></sect2>
<sect2 id="referral-bind"><title>Binding When Following Referrals</title>
<indexterm>
<primary>authentication</primary>
<secondary>authenticating during referrals</secondary>
</indexterm><indexterm>
<primary>referrals</primary>
<secondary>authenticating</secondary>
</indexterm>
<para>If the connection is set up so that referrals are always followed, the
LDAP server that you connect to can refer you to another server. By default,
the client binds anonymously such that no user names or passwords are specified
when following referrals.</para>
<para>To authenticate to the LDAP server that you are referred to, specify
how to get the DN and password for authentication. You need to define a class
that implements the <classname>LDAPRebind</classname> interface. Then, specify
an object of this new class with either of two methods. Use the <literal>LDAPv3.REFERRALS_REBIND_PROC
</literal> preference with the <literal>setOption</literal> method of the <classname>
LDAPConnection</classname> object to set the preference for all LDAP operations.
Alternatively, use the <literal>setRebindProc</literal> method of the <classname>
LDAPConstraints</classname> object to change the behavior for a specific search
request.</para>
<para>The <classname>LDAPRebind</classname> interface specifies a <literal>getRebindAuthentication
</literal> method that returns an <classname>LDAPRebindAuth</classname> object.
The <literal>getRebindAuthentication</literal> method and the <classname>LDAPRebindAuth
</classname> object that the method returns are used to get the DN and password
for authentication.</para>
<orderedlist>
<para>The following steps explain how this works.</para>
<listitem><para>The LDAP server sends a referral back to the client. The referral
contains an LDAP URL that points to another LDAP server.</para></listitem>
<listitem><para>The client creates a new <classname>LDAPConnection</classname> object.
</para></listitem>
<listitem><para>The client connects to the host and port specified in the
LDAP URL.</para></listitem>
<listitem><para>You can use the <literal>getRebindProc</literal> method to
find your object, the object that implements the <classname>LDAPRebind</classname> interface.
The client then invokes the <literal>getRebindAuthentication</literal> method,
passing in the host and port specified in the LDAP URL.</para></listitem>
<listitem><para>The <literal>getRebindAuthentication</literal> method in your
object returns an <classname>LDAPRebindAuth</classname> object.</para>
</listitem>
<listitem><para>The client invokes the <literal>getDN</literal> and <literal>getPassword
</literal> methods of the returned <classname>LDAPRebindAuth</classname> object
to get the DN and password to use for authentication.</para></listitem>
<listitem><para>The client invokes the authenticate method of the <classname>LDAPConnection
</classname> object and passes the DN and password to authenticate to the
server.</para></listitem>
</orderedlist>
<itemizedlist>
<para>Basically, you need to define the following:</para>
<listitem><para>A class that implements the <classname>LDAPRebind</classname> interface
</para></listitem>
<listitem><para>A <literal>getRebindAuthentication</literal> that takes a
host name and port number. </para></listitem>
<listitem><para>This method creates an <classname>LDAPRebindAuth</classname> object
that specifies the DN and password to use for authentication.</para></listitem>
</itemizedlist>
</sect2>
</sect1>
<sect1 id="in-memory-cache"><title>Using In-Memory Cache With &DirectorySDKForJava;</title>
<indexterm>
<primary>cache</primary>
</indexterm><indexterm>
<primary>in-memory cache</primary>
</indexterm><indexterm>
<primary>connection</primary>
<secondary>caching results</secondary>
</indexterm><indexterm>
<primary>LDAP session</primary>
<secondary>caching results</secondary>
</indexterm><indexterm>
<primary>search results</primary>
<secondary>caching</secondary>
</indexterm>
<para>&DirectorySDKForJava; includes an <classname>LDAPCache</classname> class
that allows you to create an in-memory cache of search results for your client.
When you send a search request, you receive results. The search request and
its results are then cached. The next time your client issues the same search
request, the results are read from the cache.</para>
<sect2 id="understanding-cache"><title>How the Cache Operates</title>
<itemizedlist>
<para>Each item in the cache represents a search request and its results.
When you create the cache, you can specify the maximum size of the cache.
You can also specify the maximum amount of time that an item can be cached.</para>
<listitem><para>When an item's age exceeds that time limit, the item is removed
from the cache. The cache is checked once a minute for expired items.</para>
</listitem>
<listitem><para>If adding a new item causes the cache to exceed its maximum
size, items are removed from the cache. Removal makes space for the new item.
Items are removed on a first in, first out basis.</para></listitem>
</itemizedlist>
<itemizedlist>
<para>Each item is uniquely identified by the search criteria, which includes
the following:</para>
<listitem><para>Host name and port number of the LDAP server</para></listitem>
<listitem><para>Base DN of the search</para></listitem>
<listitem><para>Search filter</para></listitem>
<listitem><para>Scope of the search</para></listitem>
<listitem><para>Attributes to be returned in the search results</para>
</listitem>
<listitem><para>DN used to authenticate the client when binding to the server</para>
</listitem>
<listitem><para>LDAP v3 controls specified in the search request</para>
</listitem>
</itemizedlist>
<para>After a search request is cached, if your client performs the same search
again, the results are read from the cache instead of from the server.</para>
<para>Note that if any part of a search request differs from a cached search
request, the results are read from the server. For example, a different DN
might be used when authenticating to the server. Alternatively, the search
request might specify that a different set of attributes should be returned.
In either case, the results are not read from the cache. Instead, the search
request is sent to the server.</para>
<para>Finally, when creating the cache, you can specify a list of the base
DNs in search requests that you want to cache. For example, if you specify <literal>
ou=People,dc=example,dc=com</literal> as a base DN to cache, your client caches
search requests where the base DN is <literal>ou=People,dc=example,dc=com</literal>.
</para></sect2>
<sect2 id="cache-setup"><title>Setting Up an In-Memory Cache</title>
<indexterm>
<primary>cache</primary>
<secondary>setting up</secondary>
</indexterm>
<orderedlist>
<para>To set up a cache for your connection, do the following:</para>
<listitem><para>Construct a new <classname>LDAPCache</classname> object that
represents the cache.</para></listitem>
<listitem><para>Invoke the <literal>setCache</literal> method of an <classname>LDAPConnection
</classname> object to associate the cache with the connection.</para>
</listitem>
</orderedlist>
<para>For example, the following section of code creates a cache with the
maximum size of 1 Mbyte. Items in the cache expire and are automatically removed
after one hour.</para>
<programlisting>try {
&nbsp;&nbsp;&nbsp;&nbsp;LDAPConnection ld = new LDAPConnection();
&nbsp;&nbsp;&nbsp;&nbsp;/* Create a cache for the connection */
&nbsp;&nbsp;&nbsp;&nbsp;int MAX_TIME_CACHED = 3600; // 3600 seconds == 1 hour
&nbsp;&nbsp;&nbsp;&nbsp;int MAX_SIZE = 1000000;&nbsp;&nbsp;&nbsp;&nbsp; // 1000000 bytes == 1 MB
&nbsp;&nbsp;&nbsp;&nbsp;LDAPCache myCache = new LDAPCache(MAX_TIME_CACHED, MAX_SIZE);
&nbsp;&nbsp;&nbsp;&nbsp;ld.setCache(myCache);
&nbsp;&nbsp;&nbsp;&nbsp;/* Connect to server */
&nbsp;&nbsp;&nbsp;&nbsp;ld.connect("ldap.example.com", LDAPv3.DEFAULT_PORT);
&nbsp;&nbsp;&nbsp;&nbsp;/*
&nbsp;&nbsp;&nbsp;&nbsp; * Perform operations...
&nbsp;&nbsp;&nbsp;&nbsp; */
} catch (LDAPException e) {
&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("Error: " + e.toString());
}</programlisting>
</sect2>
<sect2 id="caching-basedn"><title>Caching Requests by Base DN</title>
<para>If you do not want all search requests cached, specify an array of base
DNs for search requests to cache in the <classname>LDAPCache</classname> constructor.
</para>
<para>For example, the following section of code constructs a cache that only
tracks search requests that specify the base DNs <literal>ou=People,dc=example,dc=com
</literal> and <literal>ou=Groups,dc=example,dc=com</literal>.</para>
<programlisting>/* Create a cache for the connection */
int MAX_TIME_CACHED = 3600;
int MAX_SIZE = 1000000;
String [] BASE_DN_CACHED = {"ou=People,dc=example,dc=com",
&nbsp;&nbsp;&nbsp;&nbsp;"ou=Groups,dc=example,dc=com"};
LDAPCache myCache = new LDAPCache(MAX_TIME_CACHED, MAX_SIZE,
&nbsp;&nbsp;&nbsp;&nbsp;BASE_DN_CACHED);</programlisting>
</sect2>
<sect2 id="sharing-cache"><title>Sharing a Cache Among Connections</title>
<indexterm>
<primary>cache</primary>
<secondary>sharing between connections</secondary>
</indexterm>
<para>You can also share the same in-memory cache among different connections.</para>
<itemizedlist>
<listitem><para>Invoke the <literal>getCache</literal> method of an <classname>LDAPConnection
</classname> object to get the <classname>LDAPCache</classname> object that
is used.</para></listitem>
<listitem><para>Invoke the <literal>setCache</literal> method of a different <classname>
LDAPConnection</classname> object to associate the retrieved <classname>LDAPCache
</classname> object with the connection.</para></listitem>
</itemizedlist>
<para>When you clone an <classname>LDAPConnection</classname> object, the
new object automatically shares the same <classname>LDAPCache</classname> object
with the original object.</para></sect2>
<sect2 id="flushing-cache"><title>Flushing the Cache</title>
<indexterm>
<primary>cache</primary>
<secondary>flushing</secondary>
</indexterm>
<para>To flush items from the cache, invoke the <literal>flushEntries</literal> method
of the <classname>LDAPCache</classname> object. You can flush either selected
items or all items from the cache.</para>
<itemizedlist>
<listitem><para>To flush selected items from the cache, specify the base DN
of the search requests that you want to flush. Specify a DN and search scope
as arguments to the <literal>flushEntries</literal> method. If the base DN
of a cached search request falls within the scope you specified, the search
request is flushed from the cache.</para></listitem>
</itemizedlist>
<para>For example, the following section of code flushes selected search requests
from the cache. If the base DN of a search request falls under the <literal>ou=People,dc=example,dc=com
</literal> subtree, the item is removed from the cache.</para>
<programlisting>LDAPCache myCache;
/* Perform search requests... */
/*
* Flush search requests with base DNs under
* ou=People,dc=example,dc=com.
*/
myCache.flushEntries("ou=People,dc=example,dc=com",
&nbsp;&nbsp;&nbsp;&nbsp;LDAPConnection.SCOPE_SUB);</programlisting>
<itemizedlist>
<listitem><para>To flush all items from the cache, pass <literal>null</literal> as
the first argument of the <literal>flushEntries</literal> method:</para>
</listitem>
</itemizedlist>
<programlisting>myCache.flushEntries(null, 0);</programlisting>
</sect2>
<sect2 id="cache-stats"><title>Getting Cache Statistics</title>
<indexterm>
<primary>cache</primary>
<secondary>getting statistics</secondary>
</indexterm>
<itemizedlist>
<para>You can invoke the following methods of the <classname>LDAPCache</classname> object
to get statistics on the cache.</para>
<listitem><para>To get the total amount of available space in bytes that are
left in the cache, invoke the <literal>getAvailableSize</literal> method.</para>
</listitem>
<listitem><para>To get the array of base DNs of the search requests to be
cached, invoke the <literal>getBaseDNs</literal> method.</para></listitem>
<listitem><para>To get the total number of items that have been flushed from
the cache, not including items flushed when invoking the <literal>flushEntries</literal> method,
invoke the <literal>getNumFlushes</literal> method.</para></listitem>
<listitem><para>To get the maximum size of the cache in bytes, invoke the <literal>
getSize</literal> method.</para></listitem>
<listitem><para>To get the maximum amount of time that an item can be cached
in seconds, get the <literal>getTimeToLive</literal> method.</para></listitem>
</itemizedlist>
<itemizedlist>
<para>You can also get a running count of the number of requests that access
the cache.</para>
<listitem><para>To get the total number of requests for retrieving items from
the cache, invoke the <literal>getTotalOperation</literal> method.</para>
</listitem>
<listitem><para>To get the total number of requests that retrieved an item
from the cache, invoke the <literal>getNumHits</literal> method.</para>
</listitem>
<listitem><para>To get the total number of requests that failed to find and
retrieve an item from the cache, invoke the <literal>getNumMisses</literal> method.
</para></listitem>
</itemizedlist>
<para>For example, the following section of code gets and prints cache statistics.
</para>
<programlisting>LDAPConnection ld;
if ((ld != null) &amp;&amp; ld.isConnected()) {
&nbsp;&nbsp;&nbsp;&nbsp;LDAPCache connCache = ld.getCache();
&nbsp;&nbsp;&nbsp;&nbsp;if (connCache != null) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("Cache size:\t\t" +
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;connCache.getSize()/1000 + " kbytes");
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("Available:\t\t" +
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;connCache.getAvailableSize()/1000 + " kbytes");
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println( "Maximum age:\t\t" +
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;connCache.getTimeToLive()/1000 + " seconds");
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("Total hits:\t\t" +
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;connCache.getNumHits() + " hits" );
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("Total misses:\t\t" +
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;connCache.getNumMisses() + " misses" );
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("Total requests:\t\t" +
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;connCache.getTotalOperations() + " requests");
&nbsp;&nbsp;&nbsp;&nbsp;} else {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"No cache associated with the connection.");
&nbsp;&nbsp;&nbsp;&nbsp;}
}</programlisting>
</sect2>
</sect1>
<sect1 id="cloning-connection"><title>Cloning a Connection With &DirectorySDKForJava;</title>
<indexterm>
<primary>connection</primary>
<secondary>cloning</secondary>
</indexterm>
<para>You can create several <classname>LDAPConnection</classname> objects
that share a single physical network connection to the LDAP server by invoking
the <literal>LDAPConnection.clone</literal> method.</para>
<itemizedlist>
<para>Clones have the following properties:</para>
<listitem><para>If you clone an object before a connection is made to the
server, the cloned object does not share the same connection as the original
object.</para></listitem>
<listitem><para>Each clone can disconnect from the server without affecting
the connection for the other clones. The network connection remains in an
open state until all clones have either disconnected or gone out of scope.</para>
</listitem>
<listitem><para>If the clone disconnects or reconnects, the clone is completely
dissociated from the source object and other clones.</para></listitem>
<listitem><para>A cloned <classname>LDAPConnection</classname> object has
a separate set of session preferences and constraints. In other words, the
clone is associated with its own <classname>LDAPSearchConstraints</classname> object.
Changes to an option or to a search constraint only affect requests issued
using that object.</para><para>For example, suppose an <classname>LDAPConnection</classname> object
allows a maximum of 100 results to be returned from a search. If you clone
an <classname>LDAPConnection</classname> object, you can change the maximum
number of results in the clone from 100 to 200. Yet, the initial object still
allows only 100 results to be returned.</para></listitem>
<listitem><para>All clones are authenticated to the server as the same user.
If you authenticate again to the server as a different user, the current clone
is disconnected. The clone connects separately to the server. The <classname>LDAPConnection
</classname> object is no longer a clone of another <classname>LDAPConnection</classname> object.
</para></listitem>
</itemizedlist>
</sect1>
<sect1 id="handling-dns"><title>Manipulating Distinguished Names With &DirectorySDKForJava;</title>
<indexterm>
<primary>distinguished names</primary>
<secondary>manipulating</secondary>
</indexterm>
<para>A distinguished name (DN) uniquely identifies an entry in the directory
tree. You can get the DN for an entry as explained in <olink
type="auto-generated" targetptr="searching-results-dns">Getting Distinguished
Names</olink>. Alternatively, you can specify a DN to read an entry from the
directory as explained in <olink type="auto-generated" targetptr="searching-read">
Reading an Entry With Directory SDK for Java</olink>. &DirectorySDKForJava; includes
a utility class, <classname>LDAPDN</classname>, that provides
methods for manipulating DNs.</para>
<para>If you want to access individual components of a distinguished name
or a relative distinguished name, invoke the <literal>LDAPDN.explodeDN</literal> method
or the <literal>LDAPDN.explodeRDN</literal> method.</para>
<para>Both methods return an array of <classname>String</classname> objects
that represent the individual components of the distinguished name.</para>
<para>You can specify whether or not you want the names of the components
included in the array by using the <parameter>notypes</parameter> parameter.</para>
<itemizedlist>
<listitem><para>Set <parameter>notypes</parameter> to <literal>false</literal> if
you want to include component attribute types in the array.</para>
<programlisting>LDAPDN.explodeDN("uid=bjensen,ou=People,dc=example,dc=com", false);
</programlisting>
<para>The method returns the array <literal>{"uid=bjensen", "ou=People", "dc=example",
"dc=com"}</literal>.</para></listitem>
<listitem><para>Set <parameter>notypes</parameter> to <literal>true</literal> if
you do not want component attribute types returned in the array.</para>
<programlisting>LDAPDN.explodeDN("uid=bjensen,ou=People,dc=example,dc=com", true);
</programlisting>
<para>The method returns the array <literal>{"bjensen", "People", "example",
"com"}</literal>.</para></listitem>
</itemizedlist>
</sect1>
</chapter>

View File

@@ -0,0 +1,123 @@
<!--
Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
Portions copyright 1999 Netscape Communications Corporation. All
Rights Reserved.
The contents of this document are subject to the terms of the
Creative Commons Attribution-ShareAlike 2.5 license or any later
version (the "License"). You may not use this document except in
compliance with the License.
See the License for the specific language governing
permissions and limitations under the License. You can obtain
a copy of the License at
http://creativecommons.org/licenses/by-sa/2.5/legalcode.
-->
<chapter id="comparing"><title>Comparing Attribute Values With &DirectorySDKForJava;</title>
<indexterm>
<primary>attributes</primary>
<secondary>comparing values</secondary>
</indexterm><indexterm>
<primary>comparing attribute values</primary>
</indexterm><highlights>
<para>This chapter explains how to compare the value of an attribute in an
entry against a specified value.</para>
<itemizedlist>
<para>This chapter covers the following topics:</para>
<listitem><para><olink targetptr="compare-specify-attr-value">Specifying the
Attribute and Value With Directory SDK for Java</olink></para></listitem>
<listitem><para><olink targetptr="compare-perform">Performing the Comparison
With Directory SDK for Java</olink></para></listitem>
<listitem><para><olink targetptr="compare-example">Example Attribute Value
Comparison With Directory SDK for Java</olink></para></listitem>
</itemizedlist>
<para>The LDAP Java classes allow you to compare a specified value against
the value of an entry in the directory. For example, you can check to see
if the <literal>mail</literal> attribute of an entry contains the value <literal>
bjensen@example.com</literal>.</para>
<orderedlist>
<para>To compare a specified value against an attribute of an entry in the
directory, you need to follow this general procedure.</para>
<listitem><para>Specify the name of the attribute that you want to check and
the value that you want to use for comparison.</para></listitem>
<listitem><para>Use the distinguished name of the entry to find the entry
in the directory. The entry that is found is then used to perform the comparison.
</para></listitem></orderedlist>
</highlights>
<sect1 id="compare-specify-attr-value"><title>Specifying the Attribute and
Value With &DirectorySDKForJava;</title>
<para>Use an <classname>LDAPAttribute</classname> object to specify the name
of the attribute to check. Also use the object to specify the value to use
in the comparison.</para>
<programlisting>LDAPAttribute attr = new LDAPAttribute("mail", "bjensen@example.com");
</programlisting>
</sect1>
<sect1 id="compare-perform"><title>Performing the Comparison With &DirectorySDKForJava;</title>
<para>To perform the comparison, use the <literal>compare</literal> method
of the <classname>LDAPConnection</classname> object. Specify the distinguished
name of the entry that you want to compare. The method returns <literal>true</literal> if
the attribute contains the specified value.</para>
<programlisting>try {
LDAPConnection ld = new LDAPConnection();
ld.connect("localhost", LDAPv3.DEFAULT_PORT);
LDAPAttribute attr = new LDAPAttribute("mail", "bjensen@example.com");
if (ld.compare("uid=bjensen,ou=People,dc=example,dc=com", attr)) {
System.out.println("Found a match.");
}
} catch (LDAPException e) {
System.err.println("Error:" + e.toString());
}</programlisting>
</sect1>
<sect1 id="compare-example"><title>Example Attribute Value Comparison With &DirectorySDKForJava;</title>
<para>The following example compares values for the <literal>objectclass</literal> attribute
with values on Barbara Jensen's entry.</para>
<programlisting>import netscape.ldap.*;
import java.util.*;
public class Compare {
public static void main(String[] args) {
try {
UserArgs userArgs = new UserArgs("Compare", args, false);
LDAPConnection ld = new LDAPConnection();
ld.connect(userArgs.getHost(), userArgs.getPort());
/* Entry to compare */
String ENTRYDN = "uid=bjensen,ou=People,dc=example,dc=com";
/* Compare the value "person" and the attr. "objectclass" */
LDAPAttribute attr =
new LDAPAttribute("objectclass", "person");
boolean ok = ld.compare(ENTRYDN, attr);
reportResults(ok, attr);
/* Compare the value "xyzzy" and the attr. objectclass */
attr = new LDAPAttribute("objectclass", "xyzzy");
ok = ld.compare(ENTRYDN, attr);
reportResults(ok, attr);
ld.disconnect();
} catch(LDAPException e) {
System.out.println("Error: " + e.toString());
}
}
private static void reportResults(boolean ok, LDAPAttribute attr) {
String result;
if (ok) {
result = new String();
} else {
result = new String("not ");
}
Enumeration en = attr.getStringValues();
if (en != null) {
String val = (String)en.nextElement();
System.out.println(
"The value *" + val + "* is " + result +
"contained in the " + attr.getName() + " attribute.");
}
}
}</programlisting>
</sect1>
</chapter>

View File

@@ -0,0 +1,940 @@
<!--
Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
Portions copyright 1999 Netscape Communications Corporation. All
Rights Reserved.
The contents of this document are subject to the terms of the
Creative Commons Attribution-ShareAlike 2.5 license or any later
version (the "License"). You may not use this document except in
compliance with the License.
See the License for the specific language governing
permissions and limitations under the License. You can obtain
a copy of the License at
http://creativecommons.org/licenses/by-sa/2.5/legalcode.
-->
<chapter id="controls"><title>LDAP Controls With &DirectorySDKForJava;</title>
<highlights>
<para>This chapter explains how LDAP controls work and how to use the LDAP
controls.</para>
<itemizedlist>
<para>This chapter covers the following topics:</para>
<listitem><para><olink targetptr="controls-overview">How LDAP Controls Work
With Directory SDK for Java</olink></para></listitem>
<listitem><para><olink targetptr="controls-using">Using Controls in the LDAP
Java Classes</olink></para></listitem>
<listitem><para><olink targetptr="controls-server">Determining the Controls Supported the Server With Directory SDK for Java</olink></para></listitem>
<listitem><para><olink targetptr="controls-sort">Using the Server-Side Sorting
Control With Directory SDK for Java</olink></para></listitem>
<listitem><para><olink targetptr="controls-psearch">Using the Persistent Search
Control With Directory SDK for Java</olink></para></listitem>
<listitem><para><olink targetptr="controls-entry-change">Using the Entry Change
Notification Control With Directory SDK for Java</olink></para></listitem>
<listitem><para><olink targetptr="controls-vlv">Using the Virtual List Control With Directory SDK for Java</olink></para></listitem>
<listitem><para><olink targetptr="controls-managedsait">Using the Manage DSA
IT Control With Directory SDK for Java</olink></para></listitem>
<listitem><para><olink targetptr="controls-pwp">Using Password Policy Controls
With Directory SDK for Java</olink></para></listitem>
<listitem><para><olink targetptr="controls-proxyauth">Using the Proxied Authorization
Control With Directory SDK for Java</olink></para></listitem>
</itemizedlist>
</highlights>
<sect1 id="controls-overview"><title>How LDAP Controls Work With &DirectorySDKForJava;</title>
<para>LDAP v3 allows clients and servers to use controls as a mechanism for
extending an LDAP operation. A control is a way to specify additional information
as part of a request and a response.</para>
<para>For example, a client can send a control to a server as part of a search
request. The control indicates that the server should sort the search results
before sending the results back to the client.</para>
<para>Servers can also send controls back to clients. For example, the server
can send a control back to a client during the authentication process. The
control can indicate that the client password has expired. The control can
alternatively indicate that the client password is going to expire.</para>
<itemizedlist>
<para>A control specifies the following information:</para>
<listitem><para>A unique object identifier (OID)</para></listitem>
<listitem><para>An indication of whether the control is critical to the operation
</para></listitem>
<listitem><para>Optional data related to the control, such as the server-side
sorting control, where attributes used for sorting search results are needed</para>
</listitem>
</itemizedlist>
<para>The OID identifies the control. If you plan to use a control, you need
to make sure that the server supports the control. Refer to <olink targetptr="controls-server">Determining the Controls Supported the Server With Directory SDK for Java</olink> for instructions.</para>
<itemizedlist>
<para>When your client includes a control in a request for an LDAP operation,
the server can respond in one of the following ways:</para>
<listitem><para>If the server supports this control and if the control is
appropriate, the server should use the control when performing the operation.</para>
</listitem>
<listitem>
<itemizedlist>
<para>If the server does not support the control type or if the control is
not appropriate, the server should do one of the following:</para>
<listitem><para>If the control is marked as critical to the operation, the
server should not perform the operation. Instead, the server should send an <firstterm>
unavailable critical extension</firstterm> result code. When receiving this
result code, your client returns an <classname>LDAPException</classname> with
the result code <returnvalue>LDAPException.UNAVAILABLE_CRITICAL_EXTENSION</returnvalue>.
</para></listitem>
<listitem><para>If the control is marked as not critical to the operation,
the server should ignore the control. The server should proceed to perform
the operation.</para></listitem>
</itemizedlist>
</listitem>
</itemizedlist>
<para>Servers can also send controls back to clients.</para>
<itemizedlist>
<para>Two types of controls exist:</para>
<listitem><para>Server controls can be included in requests sent by clients
and in responses sent by servers.</para></listitem>
<listitem><para>Client controls affect the behavior of the LDAP Java classes
only and are never sent to the server.</para><para>&DirectorySDKForJava; does
not support client controls.</para></listitem>
</itemizedlist>
</sect1>
<sect1 id="controls-using"><title>Using Controls in the LDAP Java Classes</title>
<para>This section describes how controls are implemented in the LDAP Java
classes. This section also describes which methods to use to create, send,
and parse data from LDAP controls.</para>
<para>In the LDAP Java classes, a control is represented by an object of the <classname>
LDAPControl</classname> class.</para>
<orderedlist>
<para>To include a control in a request, do the following:</para>
<listitem><para>Invoke the <literal>getSearchConstraints</literal> method
of the <classname>LDAPConnection</classname> object to get a clone of <classname>
LDAPSearchConstraints</classname> for this connection.</para></listitem>
<listitem><para>Invoke the <literal>setServerControls</literal> method of
the cloned constraints object, passing in the <classname>LDAPControl</classname> object
that represents the control to include.</para></listitem>
<listitem><para>Invoke the appropriate method to perform the LDAP operation,
passing in the constraints object.</para><para>For example, if you are performing
a search, invoke the <literal>search</literal> method. Pass the search constraints
as an argument.</para></listitem></orderedlist>
<para>You can also include controls by invoking the <literal>setServerControls</literal> method
for the default set of search constraints. Alternatively, invoke the <literal>setOption
</literal> method to set the <constant>LDAPv3.SERVERCONTROLS</constant> option.
These controls are sent to the server with every request, however. In general,
controls tend to be specific to a type of operation. Include a control in
a request only for the operation to which the control applies.</para>
<para>You can then retrieve data from the returned controls through accessor
methods in the <classname>LDAPControl</classname> object.</para></sect1>
<sect1 id="controls-server"><title>Determining the Controls Supported the
Server With &DirectorySDKForJava;</title>
<para>LDAP v3 states that servers should list any controls that servers support
in the <literal>supportedControl</literal> attribute in the root DSE. The
following OIDs have corresponding constants that are defined in the LDAP Java
classes.</para>
<variablelist termlength="wholeline">
<varlistentry><term><literal>1.2.840.113556.1.4.473</literal></term><term><constant>
netscape.ldap.controls.LDAPSortControl.SORTREQUEST</constant></term>
<listitem><para>For instructions on using this control, refer to <olink targetptr="controls-sort">Using the Server-Side Sorting Control With Directory SDK for Java</olink>.</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>2.16.840.1.113730.3.4.2</literal></term><term><constant>
netscape.ldap.LDAPControl.MANAGEDSAIT</constant></term>
<listitem><para>For instructions on using this control, refer to <olink type="auto-generated" targetptr="controls-managedsait">Using the Manage DSA
IT Control With Directory SDK for Java</olink>.</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>2.16.840.1.113730.3.4.3</literal></term><term><constant>
netscape.ldap.controls.LDAPPersistSearchControl.PERSISTENTSEARCH</constant></term>
<listitem><para>For instructions on using this control, refer to <olink type="auto-generated" targetptr="controls-psearch">Using the Persistent Search
Control With Directory SDK for Java</olink>.</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>2.16.840.1.113730.3.4.4</literal></term><term><constant>
netscape.ldap.LDAPControl.PWEXPIRED</constant></term>
<listitem><para>For instructions on using this control, refer to <olink type="auto-generated" targetptr="controls-pwp">Using Password Policy Controls
With Directory SDK for Java</olink>.</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>2.16.840.1.113730.3.4.5</literal></term><term><constant>
netscape.ldap.LDAPControl.PWEXPIRING</constant></term>
<listitem><para>For instructions on using this control, refer to <olink type="auto-generated" targetptr="controls-pwp">Using Password Policy Controls
With Directory SDK for Java</olink>.</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>2.16.840.1.113730.3.4.9</literal></term><term><constant>
netscape.ldap.controls.LDAPVirtualListControl.VIRTUALLIST</constant></term>
<listitem><para>For instructions on using this control, refer to <olink type="auto-generated" targetptr="controls-vlv">Using the Virtual List Control With Directory SDK for Java</olink>.</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>2.16.840.1.113730.3.4.12</literal></term><term><constant>
netscape.ldap.controls.LDAPProxiedAuthControl.PROXIEDAUTHREQUEST</constant></term>
<listitem><para>For instructions on using this control, refer to <olink targetptr="controls-proxyauth">Using the Proxied Authorization Control With Directory SDK for Java</olink>.</para>
</listitem>
</varlistentry>
</variablelist>
<para>The following example searches for the root DSE. Then the example prints
the values of the <literal>supportedControl</literal> attribute.</para>
<programlisting>import netscape.ldap.*;
import netscape.ldap.controls.*;
import java.util.*;
public class ListCtrl {
public static void main(String[] args) {
/* Hashtable mapping OIDs of controls to a description */
Hashtable knownControls = new Hashtable();
knownControls.put(LDAPSortControl.SORTREQUEST,
"Sort control");
knownControls.put(LDAPControl.MANAGEDSAIT,
"ManageDsaIT control");
knownControls.put(LDAPPersistSearchControl.PERSISTENTSEARCH,
"Persistent Search control");
knownControls.put(LDAPControl.PWEXPIRED,
"Password Expiration Notification control");
knownControls.put(LDAPControl.PWEXPIRING,
"Password Expiration Warning control");
knownControls.put(LDAPVirtualListControl.VIRTUALLIST,
"Virtual List View control");
knownControls.put(LDAPProxiedAuthControl.PROXIEDAUTHREQUEST,
"Proxied Authorization control");
try {
UserArgs userArgs = new UserArgs("ListCtrl", args, false);
LDAPConnection ld = new LDAPConnection();
ld.connect(userArgs.getHost(), userArgs.getPort());
/* Retreive the list of supported controls from the DSE. */
String getAttrs[] = {"supportedControl"};
LDAPSearchResults res = ld.search("", LDAPv3.SCOPE_BASE,
"(objectclass=*)", getAttrs, false);
LDAPEntry DSE = (LDAPEntry)res.nextElement();
LDAPAttributeSet findAttrs = DSE.getAttributeSet();
Enumeration enumAttrs = findAttrs.getAttributes();
while (enumAttrs.hasMoreElements()) {
LDAPAttribute anAttr =
(LDAPAttribute)enumAttrs.nextElement();
String attrName = anAttr.getName();
System.out.println(attrName);
Enumeration enumVals = anAttr.getStringValues();
if (enumVals == null) {
System.out.println("\tNo values.");
continue;
}
while (enumVals.hasMoreElements()) {
String aVal = (String)enumVals.nextElement();
/*
* Each value should be the OID of a control.
* Look up its description in the hash table.
*/
String aDesc = (String)knownControls.get(aVal);
if (aDesc != null) {
System.out.println("\t" + aDesc+ " (" + aVal + ")");
} else {
System.out.println("\t" + aVal);
}
}
}
ld.disconnect();
} catch(LDAPException e) {
System.out.println("Error: " + e.toString());
}
}
}</programlisting>
</sect1>
<sect1 id="controls-sort"><title>Using the Server-Side Sorting Control With &DirectorySDKForJava;</title>
<indexterm>
<primary>search results</primary>
<secondary>sorting</secondary>
</indexterm><indexterm>
<primary>sorting search results</primary>
</indexterm>
<para>The control represented with the OID that corresponds to the constant <constant>
netscape.ldap.LDAPControl.SORTREQUEST</constant> is a server-side sorting
control. The server-side sorting control is defined in <ulink
url="http://www.ietf.org/rfc/rfc2891.txt" type="text_url">RFC 2891</ulink>.
When you send a search request with this control to the server, the server
should sort the results before sending them back to you.</para>
<sect2 id="controls-sort-order"><title>Specifying the Server-Side Sort Order
With Directory SDK for Java</title>
<para>To specify the sort order of the results, construct one or more <classname>
LDAPSortKey</classname> objects. Each object represents a sort key that is
generated from a string in the following format:</para>
<programlisting>[-]<replaceable>attrName</replaceable>[:<replaceable>matchingRuleOID
</replaceable>]</programlisting>
<para>Here, <replaceable>attrName</replaceable> represents the name of the
attribute to use for sorting. <replaceable>matchingRuleOID</replaceable> represents
the optional OID of the matching rule to use for sorting. The optional minus
sign (<literal>-</literal>) indicates that the results should be sorted in
reverse order for that attribute.</para>
<para>For example, the following string specifies that results should be sorted
by first name (<literal>givenname</literal>) in descending order:</para>
<programlisting>-givenname</programlisting>
<para>Pass this string to the <classname>LDAPSortKey</classname> constructor
to create a sort key:</para>
<programlisting>LDAPSortKey reverseSortByFirstName = new LDAPSortKey("-givenname");
</programlisting>
<para>To sort by more than one attribute, construct more than one <classname>LDAPSortKey
</classname> object and create an array of the objects.</para>
<para>For example, suppose you want to sort the result by last name (<literal>sn</literal>)
in ascending order. If two or more entries have the same last name, you want
to sort the result by first name (<literal>givenname</literal>) in ascending
order. To specify this sort order, you construct two <classname>LDAPSortKey</classname> objects.
Then create an array:</para>
<programlisting>LDAPSortKey sortByLastName = new LDAPSortKey("sn");
LDAPSortKey sortByFirstName = new LDAPSortKey("givenname");
LDAPSortKey[] sortOrder = { sortByLastName, sortByFirstName };</programlisting>
</sect2>
<sect2 id="controls-sort-create"><title>Creating the Server-Side Sorting Control
With &DirectorySDKForJava;</title>
<para>Next, to create the server-side sorting control, construct a new <classname>
LDAPSortControl</classname> object. Pass the <classname>LDAPSortKey</classname> object,
or the array of <classname>LDAPSortKey</classname> objects, to the <literal>LDAPSortControl
</literal> constructor.</para>
<para>In the constructor, you can also specify whether or not the control
is critical to the search operation. The control can be marked as critical,
but the server cannot sort the results. If the situation occurs, the server
should not send back any entries.</para>
<para>For example, the following section of code creates a server-side sorting
control. Also, the code specifies that the control is critical to the search
operation:</para>
<programlisting>LDAPSortKey sortOrder = new LDAPSortKey("-givenname");
LDAPSortControl sortCtrl = new LDAPSortControl(sortOrder, true);</programlisting>
</sect2>
<sect2 id="controls-sort-search"><title>Performing the Server&mdash;Side Sort
With &DirectorySDKForJava;</title>
<orderedlist>
<para>To specify that you want the server to sort the results, do the following:</para>
<listitem><para>Get a clone of <classname>LDAPSearchConstraints</classname> for
the current connection by invoking the <literal>getSearchConstraints</literal> method
of the <classname>LDAPConnection</classname> object.</para></listitem>
<listitem><para>Invoke the <literal>setServerControls</literal> method for
the copied <classname>LDAPSearchConstraints</classname> object, and pass in
the <classname>LDAPSortControl</classname> object that you have constructed.</para>
</listitem>
<listitem><para>Invoke the <literal>search</literal> method of the <classname>LDAPConnection
</classname> object, passing in the <classname>LDAPSearchConstraints</classname> object.
</para><para>The server returns a result for the search operation and a response
control. The response control indicates the success or failure of the sorting.</para>
</listitem>
<listitem><para>Invoke the <literal>getResponseControls</literal> method of
the <classname>LDAPSearchResults</classname> object to retrieve any controls
sent back by the server in response to the search.</para><para>Response controls
are passed back as an array of <classname>LDAPControl</classname> objects.</para>
</listitem>
<listitem><para>Examine the type of each returned control. </para></listitem>
</orderedlist>
<para>If a control is an instance of <classname>LDAPSortControl</classname>,
you can read the result code for the sorting operation with the <literal>getResultCode
</literal> method.</para>
<para>If the sorting operation failed, the server can also return the name
of the attribute that caused the failure. You can read the name of this attribute
with the <literal>getFailedAttribute</literal> method.</para>
<para>The server can return the following result codes that apply to the sorting
operation.</para>
<variablelist>
<varlistentry><term><returnvalue>LDAPException.ADMIN_LIMIT_EXCEEDED</returnvalue></term>
<listitem><para>Too many entries exist for the server to sort.</para>
</listitem>
</varlistentry>
<varlistentry><term><returnvalue>LDAPException.BUSY</returnvalue></term>
<listitem><para>The server is too busy to sort the results.</para>
</listitem>
</varlistentry>
<varlistentry><term><returnvalue>LDAPException.INAPPROPRIATE_MATCHING</returnvalue></term>
<listitem><para>The sort key list specifies a matching rule that is not recognized
or appropriate.</para>
</listitem>
</varlistentry>
<varlistentry><term><returnvalue>LDAPException.INSUFFICIENT_ACCESS_RIGHTS</returnvalue></term>
<listitem><para>The server did not send the sorted results because the client
has insufficient access rights.</para>
</listitem>
</varlistentry>
<varlistentry><term><returnvalue>LDAPException.NO_SUCH_ATTRIBUTE</returnvalue></term>
<listitem><para>The sort key list specifies an attribute that does not exist.</para>
</listitem>
</varlistentry>
<varlistentry><term><returnvalue>LDAPException.OPERATION_ERROR</returnvalue></term>
<listitem><para>An internal server error occurred.</para>
</listitem>
</varlistentry>
<varlistentry><term><returnvalue>LDAPException.OTHER</returnvalue></term>
<listitem><para>This general result code indicates that the server failed
to sort the results for a reason other than the results listed here.</para>
</listitem>
</varlistentry>
<varlistentry><term><returnvalue>LDAPException.STRONG_AUTH_REQUIRED</returnvalue></term>
<listitem><para>The server refused to send back the sorted search results
because the server requires that you use a stronger authentication method.</para>
</listitem>
</varlistentry>
<varlistentry><term><returnvalue>LDAPException.SUCCESS</returnvalue></term>
<listitem><para>The results were sorted successfully.</para>
</listitem>
</varlistentry>
<varlistentry><term><returnvalue>LDAPException.TIME_LIMIT_EXCEEDED</returnvalue></term>
<listitem><para>The maximum time allowed for a search was exceeded before
the server finished sorting the results.</para>
</listitem>
</varlistentry>
<varlistentry><term><returnvalue>LDAPException.UNWILLING_TO_PERFORM</returnvalue></term>
<listitem><para>The server is unable to sort the results.</para>
</listitem>
</varlistentry>
</variablelist>
</sect2>
<sect2 id="controls-sort-results"><title>Interpreting the Server-Side Sort
Results With &DirectorySDKForJava;</title>
<para>The following table shows the kinds of results to expect from the LDAP
server under different conditions.</para>
<table frame="topbot" pgwide="1" id="controls-sort-results-interpret"><title>Server
Responses to Sort Controls</title>
<tgroup cols="4" colsep="0" rowsep="0"><colspec colwidth="25*"><colspec
colwidth="25*"><colspec colwidth="25*"><colspec colwidth="25*">
<thead>
<row rowsep="1">
<entry colsep="0">
<para>Supports sort control?</para></entry>
<entry colsep="0">
<para>Sort control marked critical?</para></entry>
<entry colsep="0">
<para>Any other conditions?</para></entry>
<entry colsep="0">
<para>Results From LDAP Server</para></entry>
</row>
</thead>
<tbody>
<row>
<entry colsep="0">
<para>Server does not support sort control.</para></entry>
<entry colsep="0">
<para>Control is not marked as critical.</para></entry>
<entry colsep="0">
<para>Not applicable</para></entry>
<entry colsep="0">
<para>The server ignores the sorting control. The server returns the entries
unsorted.</para></entry>
</row>
<row>
<entry colsep="0">
<para>Server does not support sort control.</para></entry>
<entry colsep="0">
<para>Control is marked as critical.</para></entry>
<entry colsep="0">
<para>Not applicable</para></entry>
<entry colsep="0">
<para>The server does not send back any entries.</para></entry>
</row>
<row>
<entry colsep="0">
<para>Server does support sort control.</para></entry>
<entry colsep="0">
<para>Control is not marked as critical.</para></entry>
<entry colsep="0">
<para>The server cannot sort the results with the specified sort key list.</para>
</entry>
<entry colsep="0">
<itemizedlist>
<listitem><para>The server returns the entries unsorted.</para></listitem>
<listitem><para>The server sends back the sorting response control. The response
control specifies the result code of the sort attempt and, optionally, the
attribute type that caused the error.</para></listitem>
</itemizedlist>
</entry>
</row>
<row>
<entry colsep="0">
<para>Server does support sort control.</para></entry>
<entry colsep="0">
<para>Control is marked as critical.</para></entry>
<entry colsep="0">
<para>The server cannot sort the results with the specified sort key list.</para>
</entry>
<entry colsep="0">
<itemizedlist>
<listitem><para>The server does not return any entries.</para></listitem>
<listitem><para>The server sends back the sorting response control. The response
control specifies the result code of the sort attempt and, optionally, the
attribute type that caused the error.</para></listitem>
</itemizedlist>
</entry>
</row>
<row>
<entry colsep="0">
<para>Server does support sort control.</para></entry>
<entry colsep="0">
<para>has no effect on results</para></entry>
<entry colsep="0">
<para>The search failed.</para></entry>
<entry colsep="0">
<itemizedlist>
<listitem><para>The server returns a result code for the search operation.</para>
</listitem>
<listitem><para>The server does not send back the sorting response control.</para>
</listitem>
</itemizedlist>
</entry>
</row>
<row>
<entry colsep="0">
<para>Server does support sort control.</para></entry>
<entry colsep="0">
<para>has no effect on results</para></entry>
<entry colsep="0">
<para>The server successfully sorted the entries.</para></entry>
<entry colsep="0">
<itemizedlist>
<listitem><para>The server returns the entries in sorted order.</para>
</listitem>
<listitem><para>The server sends back the sorting response control, which
specifies the result code of the sort attempt as <returnvalue>LDAPException.SUCCESS
</returnvalue>.</para></listitem>
</itemizedlist>
</entry>
</row>
</tbody>
</tgroup>
</table>
</sect2>
<sect2 id="controls-sort-example"><title>Example of Using Server-Side Sorting
With &DirectorySDKForJava;</title>
<para>The following sample program uses the server-side sorting control to
get a list of all users in the directory. The list is sorted in ascending
order by last name, then in descending order by first name.</para>
<programlisting>import netscape.ldap.*;
import netscape.ldap.controls.*;
import java.util.*;
public class SrchSort {
public static void main(String[] args) {
try {
UserArgs userArgs = new UserArgs("SrchSort", args, false);
LDAPConnection ld = new LDAPConnection();
ld.connect(userArgs.getHost(), userArgs.getPort());
ld.authenticate(3, null, null); // Anonymous bind, LDAP v3
String filter = "sn=Jen*";
String baseDN = "ou=People,dc=example,dc=com";
String[] attrs = {"sn", "givenname"};
/* Sort by last name, then in reverse by first name. */
LDAPSortKey sortByLastName = new LDAPSortKey("sn");
LDAPSortKey sortByFirstName = new LDAPSortKey("-givenname");
LDAPSortKey[] sortOrder = {sortByLastName, sortByFirstName};
LDAPSortControl sortCtrl = new LDAPSortControl(sortOrder, true);
LDAPSearchConstraints cons = ld.getSearchConstraints();
cons.setServerControls(sortCtrl);
/* Perform the search using the control. */
LDAPSearchResults res = ld.search(baseDN, LDAPv3.SCOPE_SUB,
filter, attrs, false, cons);
/* Display the results. */
System.out.println("Sorted results from server");
System.out.println("==========================");
while (res.hasMoreElements()) {
LDAPEntry resEntry = null;
try {
resEntry = res.next();
} catch (LDAPReferralException e) {
continue; // Skip referrals for now.
} catch (LDAPException e) {
System.err.println("Error:" + e.toString());
continue;
}
LDAPAttributeSet resAttrs = resEntry.getAttributeSet();
Enumeration enumAttrs = resAttrs.getAttributes();
while (enumAttrs.hasMoreElements()) {
LDAPAttribute attr =
(LDAPAttribute)enumAttrs.nextElement();
Enumeration enumVals = attr.getStringValues();
if (enumVals == null) {
System.out.println("\tNo values.");
continue;
}
while (enumVals.hasMoreElements()) {
String val = (String)enumVals.nextElement();
System.out.print(val);
}
System.out.print(", ");
}
System.out.println("");
}
/* Check whether the server sent back a control. */
LDAPControl[] returnedControls = res.getResponseControls();
if (returnedControls != null) {
for (int i = 0; i &lt; returnedControls.length; ++i) {
if (!(returnedControls[i] instanceof LDAPSortControl)) {
continue;
}
LDAPSortControl sortRsp =
(LDAPSortControl)returnedControls[i];
int resultCode = sortRsp.getResultCode();
/* Check the result for errors. */
if (resultCode != 0) {
System.err.println("Result code: " + resultCode);
System.err.println(
LDAPException.errorCodeToString(resultCode));
/* Report attribute that caused the failure. */
String failedAttr = sortRsp.getFailedAttribute();
if (failedAttr != null) {
System.err.println("Failed on: " + failedAttr);
} else {
System.err.println("Server did not indicate " +
"which attribute caused sorting to fail.");
}
}
}
}
ld.disconnect();
} catch(LDAPException e) {
System.out.println("Error: " + e.toString());
}
}
}</programlisting>
</sect2>
</sect1>
<sect1 id="controls-psearch"><title>Using the Persistent Search Control With &DirectorySDKForJava;</title>
<indexterm>
<primary>persistent searches</primary>
</indexterm>
<para>The control represented with the OID that corresponds to the constant <constant>
netscape.ldap.LDAPControl.PERSISTENTSEARCH</constant> is a persistent search
control. A <firstterm>persistent search</firstterm>, an ongoing search operation,
allows your LDAP client to get notification of changes to the directory.</para>
<para>To use persistent searching for change notification, you create a persistent
search control that specifies the types of changes that you want to track.
You include the control in a search request. If an entry in the directory
is changed, the server determines if the entry matches the search criteria
in your request. The server also determines if the change is the type of change
that you are tracking. If both of the conditions are true, the server sends
the entry to your client.</para>
<para>You can use this control in conjunction with an entry change notification
control, as described in <olink type="auto-generated" targetptr="controls-entry-change">Using the Entry Change Notification Control
With Directory SDK for Java</olink>.</para>
<sect2 id="controls-psearch-create"><title>Creating the Persistent Search
Control With Directory SDK for Java</title>
<itemizedlist>
<para>To create a persistent search control, you construct a new <classname>LDAPPersistSearchControl
</classname> object. When invoking the <literal>LDAPPersistSearchControl</literal> constructor,
you can specify the following information:</para>
<listitem>
<itemizedlist>
<para>The type of change you want to track. You can specify any of the following,
or any combination of the following, using a bitwise OR (<literal>|</literal>)
operator:</para>
<listitem><para><literal>ADD</literal> indicates that you want to track added
entries.</para></listitem>
<listitem><para><literal>DELETE</literal> indicates that you want to track
deleted entries.</para></listitem>
<listitem><para><literal>MODDN</literal> indicates that you want to track
renamed entries.</para></listitem>
<listitem><para><literal>MODIFY</literal> indicates that you want to track
modified entries.</para></listitem>
</itemizedlist>
</listitem>
<listitem><para>A preference indicating whether you want the server to return
all entries that initially matched the search criteria</para></listitem>
<listitem><para>A preference indicating whether or not you want entry change
notification controls included with every modified entry returned by the server</para>
</listitem>
</itemizedlist>
<para>This code excerpt shows an example of creating a persistent search control.
</para>
<programlisting>/* Track all types of changes. */
int op = LDAPPersistSearchControl.ADD |
LDAPPersistSearchControl.MODIFY |
LDAPPersistSearchControl.DELETE |
LDAPPersistSearchControl.MODDN;
/* Return only entries that have changed. */
boolean changesOnly = true;
/* Return an entry change notification control. */
boolean returnControls = true;
/* Mark the control as critical. */
boolean isCritical = true;
/* Create the control. */
LDAPPersistSearchControl persistCtrl =
new LDAPPersistSearchControl(
op, changesOnly, returnControls, isCritical);</programlisting>
</sect2>
<sect2 id="controls-psearch-search"><title>Performing the Persistent Search
With Directory SDK for Java</title>
<orderedlist>
<para>To specify that you want to start a persistent search, do the following:</para>
<listitem><para>Get a clone of <classname>LDAPSearchConstraints</classname> for
the current connection by invoking the <literal>getSearchConstraints</literal> method
of the <classname>LDAPConnection</classname> object.</para></listitem>
<listitem><para>Invoke the <literal>setServerControls</literal> method for
the cloned <classname>LDAPSearchConstraints</classname> object, and pass in
the <classname>LDAPPersistSearchControl</classname> object that you have constructed.
</para></listitem>
<listitem><para>Invoke the search method of the <classname>LDAPConnection</classname> object,
passing in the <classname>LDAPSearchConstraints</classname> object.</para><para>The
server returns entries that match as the entries change. If you specified
that you wanted an entry change notification control included with each entry,
you can get these controls from the server's results. For instructions, refer
to <olink type="auto-generated" targetptr="controls-entry-change">Using the
Entry Change Notification Control With Directory SDK for Java</olink>.</para>
</listitem></orderedlist>
<para>To end the persistent search, invoke the <literal>abandon</literal> method
of the <classname>LDAPConnection</classname> object. Alternatively, invoke
the <literal>disconnect</literal> method to disconnect from the server.</para>
</sect2>
<sect2 id="controls-psearch-example"><title>Example of Using the Persistent
Search Control With Directory SDK for Java</title>
<para>The following example performs a persistent search. The example receives
entry change notification controls from the server.</para>
<programlisting>import netscape.ldap.*;
import netscape.ldap.controls.*;
import java.util.*;
public class SrchPrst implements Runnable {
private static String [] cliArgs;
public static void main(String[] args) {
cliArgs = args;
/* Start up a new thread. */
Thread th = new Thread(new SrchPrst(), "mainConn");
th.start();
System.out.println("Main thread started.");
}
public void run() {
try {
UserArgs userArgs = new UserArgs("SrchPrst", cliArgs, true);
LDAPConnection ld = new LDAPConnection();
ld.connect(userArgs.getHost(), userArgs.getPort());
ld.authenticate(3, userArgs.getBindDN(),userArgs.getPassword());
/* Create the control and search constraints. */
int op = LDAPPersistSearchControl.ADD |
LDAPPersistSearchControl.MODIFY |
LDAPPersistSearchControl.DELETE |
LDAPPersistSearchControl.MODDN;
boolean changesOnly = true;
boolean returnControls = true;
boolean isCritical = true;
LDAPPersistSearchControl persistCtrl =
new LDAPPersistSearchControl(op, changesOnly,
returnControls, isCritical);
LDAPSearchConstraints cons = ld.getSearchConstraints();
cons.setServerControls(persistCtrl);
/* Track changes on all entries. */
String filter = "(objectclass=*)";
String baseDN = "dc=example,dc=com";
/* Start the search. */
LDAPSearchResults res =
ld.search(
baseDN, LDAPv3.SCOPE_SUB, filter, null, false, cons);
/* Loop through the results until finished. */
while (res.hasMoreElements()) {
System.out.println("\n===== Changed Entry =====");
LDAPEntry findEntry = res.next();
LDAPAttributeSet findAttrs = findEntry.getAttributeSet();
Enumeration enumAttrs = findAttrs.getAttributes();
while (enumAttrs.hasMoreElements()) {
LDAPAttribute anAttr =
(LDAPAttribute)enumAttrs.nextElement();
String attrName = anAttr.getName();
System.out.println("\t" + attrName);
Enumeration enumVals = anAttr.getStringValues();
while (enumVals.hasMoreElements()) {
String aVal = (String)enumVals.nextElement();
System.out.println("\t\t" + aVal);
}
}
/* Get any entry change controls. */
LDAPControl[] responseCtrls = res.getResponseControls();
if (responseCtrls != null) {
for (int i=0; i &lt; responseCtrls.length; i++){
if (!(responseCtrls[i] instanceof
LDAPEntryChangeControl)) {
continue;
}
LDAPEntryChangeControl entryCtrl =
(LDAPEntryChangeControl) responseCtrls[i];
/* Get information on the type of change */
int changeType = entryCtrl.getChangeType();
if (changeType != -1) {
System.out.print("Change made: ");
switch (changeType) {
case LDAPPersistSearchControl.ADD:
System.out.println("Added new entry.");
break;
case LDAPPersistSearchControl.MODIFY:
System.out.println("Modified entry.");
break;
case LDAPPersistSearchControl.DELETE:
System.out.println("Deleted entry.");
break;
case LDAPPersistSearchControl.MODDN:
System.out.println("Renamed entry.");
break;
default:
System.out.println(
"Unknown change type.");
break;
}
}
/* Get the change log number, if present */
int changeNumber = entryCtrl.getChangeNumber();
if (changeNumber != -1) {
System.out.println(
"Change log number: " + changeNumber);
}
/* Get the previous DN of the entry, if
a rename operation was performed. */
String oldDN = entryCtrl.getPreviousDN();
if (oldDN != null) {
System.out.println("Previous DN: " + oldDN);
}
}
System.out.println("\n");
}
}
} catch(LDAPException e) {
System.out.println("Error: " + e.toString());
}
}
}</programlisting>
</sect2>
</sect1>
<sect1 id="controls-entry-change"><title>Using the Entry Change Notification
Control With &DirectorySDKForJava;</title>
<para>The control represented with the OID that corresponds to the constant <constant>
netscape.ldap.LDAPEntryChangeControl.ENTRYCHANGED</constant> is an <firstterm>entry
change notification</firstterm> control. These types of controls can be included
with entries sent back from the server during a persistent search.</para>
<sect2 id="controls-entry-change-get"><title>Getting the Entry Change Notification
Control With Directory SDK for Java</title>
<orderedlist>
<para>To get an entry change notification control that is included with an
entry, do the following:</para>
<listitem><para>As you retrieve each entry, invoke the <literal>getResponseControls
</literal> method of the <classname>LDAPConnection</classname> object to retrieve
any response controls sent back from the server.</para><para>Response controls
are passed back as an array of <classname>LDAPControl</classname> objects. </para>
</listitem>
<listitem><para>Pass this array of <classname>LDAPControl</classname> objects
as an argument to the <literal>LDAPPersistSearchControl.parseResponse</literal> static
method to retrieve the entry change notification control.</para></listitem>
</orderedlist>
<para>An entry change notification control is represented by an object of
the <classname>LDAPEntryChangeControl</classname> class. To get data from
this control, you can invoke the accessor methods, such as <literal>getChangeNumber
</literal>, <literal>getChangeType</literal>, and <literal>getPreviousDN</literal>.
</para></sect2>
<sect2 id="controls-entry-change-work"><title>Working With Change Log Numbers
With Directory SDK for Java</title>
<para>If the directory server is set up to be a supplier, the server is capable
of replicating changes in the directory to other servers. The server therefore
keeps a record of the changes made to the directory in a change log. Each
record of a change has a number that identifies the change in the log.</para>
<para>You can get the change number for a modified entry from the <classname>LDAPEntryChangeControl
</classname> object.</para>
<para>To look up the record for a particular change log number to get more
information about the change that took place, search for the record. With
Directory Server, the change log is represented by an entry in the directory.
Individual change records are represented by entries in a subtree beneath
the change log entry.</para>
<para>To determine the DN for the change log entry, search the root DSE to
retrieve the <literal>changelog</literal> attribute. For example, the value
of this attribute might be <literal>cn=changelog</literal>, which is the DN
for the change log entry.</para>
<para>Each change log record is an entry under the change log entry. The change
log number is the value of the <literal>changenumber</literal> attribute of
the record. To get a specific change log record, search with base DN <literal>cn=changelog
</literal> and filter <literal>changenumber=</literal><replaceable>value</replaceable>.
Here, <replaceable>value</replaceable> is the change number of the record.</para>
</sect2>
</sect1>
<sect1 id="controls-vlv"><title>Using the Virtual List Control With &DirectorySDKForJava;</title>
<para>The control represented with the OID that corresponds to the constant <constant>
netscape.ldap.controls.LDAPVirtualListControl.VIRTUALLIST</constant> is a <firstterm>
virtual list</firstterm> control. When you send a search request with this
control and with a server-side sorting control to the server, the server should
sort the results and return the specified subset of entries back to your client.</para>
<para>After you set the list size with the <literal>setListSize</literal> method
of the <classname>LDAPVirtualListControl</classname> object, invoke the <literal>
setRange</literal> method. The method recreates the control with the new data. <literal>
setRange</literal> generates the BER-encoded request to be sent to the server. <literal>
setListSize</literal> does not generate the request.</para></sect1>
<sect1 id="controls-managedsait"><title>Using the Manage DSA IT Control With &DirectorySDKForJava;</title>
<para>The control represented with the OID that corresponds to the constant <constant>
netscape.ldap.controls.LDAPControl.MANAGEDSAIT</constant> is a <firstterm>manage
DSA IT</firstterm> control. The control is for managing search references
in the directory and is defined in <ulink
url="http://www.ietf.org/rfc/rfc3296.txt" type="text_url">RFC
3296</ulink>.</para>
<para>To create this control, construct a new <classname>LDAPControl</classname> object.
In the <literal>LDAPControl</literal> constructor, set the OID of the control
to <constant>netscape.ldap.controls.LDAPControl.MANAGEDSAIT</constant>.</para>
<para>Add this control to the array of <classname>LDAPControl</classname> objects.
When you pass the array to a method that performs an LDAP operation, the server
treats search references as ordinary entries.</para>
<para>Rather than returning a reference to you, the server returns the entry
that contains the reference. This mechanism allows your client application
to manage search references in the directory.</para></sect1>
<sect1 id="controls-pwp"><title>Using Password Policy Controls With &DirectorySDKForJava;</title>
<itemizedlist>
<para>&cnDirectoryServer; uses two server response controls to send information
back to a client after an LDAP bind operation.</para>
<listitem><para>The control represented with the OID that corresponds to the
constant <constant>netscape.ldap.controls.LDAPControl.PWEXPIRED</constant> is
the <firstterm>expired password</firstterm> control.</para><para>This control
is used if the server is configured to require users to change their passwords
on first login. The control is also used whenever the passwords are reset.</para>
<para>The user might be logging in for the first time. The user password might
have been reset. In either circumstance, the server sends the control to indicate
that the client needs to change the password immediately. When receiving this
control, the only operation that the client can perform is to change the user's
password. If the client requests any other LDAP operation, the server sends
back an <returnvalue>LDAP_UNWILLING_TO_PERFORM</returnvalue> result code with
an expired password control.</para></listitem>
<listitem><para>The control represented with the OID that corresponds to the
constant <constant>netscape.ldap.controls.LDAPControl.PWEXPIRING</constant> is
the <firstterm>password expiring warning</firstterm> control.</para><para>This
control is used if the server is configured to expire user passwords after
a certain amount of time.</para><para>The server sends this control back to
the client if the client binds with a password that is soon to expire. If
you invoke the <literal>getValue</literal> method for this <classname>LDAPControl
</classname> object, the method returns the number of seconds before the password
expires.</para></listitem>
</itemizedlist>
<para>To get these server response controls when binding, invoke the <literal>getResponseControls
</literal> method of the <classname>LDAPConnection</classname> object after
you attempt to authenticate to the server.</para></sect1>
<sect1 id="controls-proxyauth"><title>Using the Proxied Authorization Control
With &DirectorySDKForJava;</title>
<para>The control represented with the OID that corresponds to the constant <constant>
netscape.ldap.controls.LDAPProxiedAuthControl.PROXIEDAUTHREQUEST</constant> is
a <firstterm>proxied authorization</firstterm> control. It allows LDAP clients
to use different credentials, without rebinding, when executing LDAP operations.</para>
<para>For example, suppose a messaging server stores its user profiles on
an LDAP server. For certain types of requests the messaging server needs to
use a DN and password other than its own. To use another DN and password without
proxied authorization requires the messaging server to rebind, using the different
credentials, before executing each operation.</para>
<para>If the messaging server uses the proxied authorization control, the
server can act as the user when executing an operation. The messaging server
maintains only its own binding to the LDAP server. This mechanism drastically
improves performance, especially when processing a large number of requests.</para>
</sect1>
</chapter>

View File

@@ -0,0 +1,156 @@
<!--
Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
Portions copyright 1999 Netscape Communications Corporation. All
Rights Reserved.
The contents of this document are subject to the terms of the
Creative Commons Attribution-ShareAlike 2.5 license or any later
version (the "License"). You may not use this document except in
compliance with the License.
See the License for the specific language governing
permissions and limitations under the License. You can obtain
a copy of the License at
http://creativecommons.org/licenses/by-sa/2.5/legalcode.
-->
<chapter id="extended-ops"><title>Extended Operations With &DirectorySDKForJava;</title>
<highlights>
<para>This chapter explains LDAP v3 extended operations. This chapter also
explains how to use the extended operations that are supported by your LDAP
server.</para>
<itemizedlist>
<para>This chapter covers the following topics:</para>
<listitem><para><olink targetptr="extops-overview">How Extended Operations
Work With Directory SDK for Java</olink></para></listitem>
<listitem><para><olink targetptr="extops-server-side">Implementing Support
for Extended Operations on the Server With Directory SDK for Java</olink></para>
</listitem>
<listitem><para><olink targetptr="extopts-view-supported">Determining the
Extended Operations Supported With Directory SDK for Java</olink></para>
</listitem>
<listitem><para><olink targetptr="extopts-client-side">Performing an Extended
Operation With Directory SDK for Java</olink></para></listitem>
<listitem><para><olink targetptr="extopts-example">Example Extended Operation
With Directory SDK for Java</olink></para></listitem>
</itemizedlist>
</highlights>
<sect1 id="extops-overview"><title>How Extended Operations Work With &DirectorySDKForJava;</title>
<para>Extended operations are part of LDAP v3. Each extended operation is
identified by an object identifier (OID).</para>
<itemizedlist>
<para>LDAP clients can request the operation by sending an extended operation
request. Within the request, the client specifies the following:</para>
<listitem><para>The OID of the extended operation to perform</para></listitem>
<listitem><para>Data specific to the extended operation</para></listitem>
</itemizedlist>
<itemizedlist>
<para>The server receives the request. The server then performs the extended
operation. The server can send back to the client a response containing:</para>
<listitem><para>An OID</para></listitem>
<listitem><para>Any additional data</para></listitem>
</itemizedlist>
<itemizedlist>
<para>To use extended operations, both the server and the client must know
the specific extended operation to be performed.</para>
<listitem><para>You must write a client that can send requests for a specific
extended operation. The client must also be able to receive extended responses
from the server.</para></listitem>
<listitem><para>Your LDAP server needs to be able to handle requests for specific
extended operations. The server also must be able to send responses back to
the client.</para></listitem>
</itemizedlist>
</sect1>
<sect1 id="extops-server-side"><title>Implementing Support for Extended Operations
on the Server With Directory SDK for Java</title>
<indexterm>
<primary>LDAP servers</primary>
<secondary>extended operations and</secondary>
</indexterm>
<para>&cnDirectoryServer; supports a plug-in API that allows you to write
your own server plug-in to handle extended operations.</para>
<itemizedlist>
<para>You can write an extended operation that does the following:</para>
<listitem><para>Registers the OID of an extended operation as supported, so
the OID appears as a value of the <literal>supportedExtension</literal> attribute
on the root DSE</para></listitem>
<listitem><para>Gets information from an extended operation request</para>
</listitem>
<listitem><para>Creates and sends an extended operation response back to the
client</para></listitem>
</itemizedlist>
</sect1>
<sect1 id="extopts-view-supported"><title>Determining the Extended Operations
Supported With &DirectorySDKForJava;</title>
<para>To determine the extended operations supported by the server, get the
root DSE of the server, and check the <literal>supportedExtension</literal> attribute.
The values of this attribute are the OIDs of the extended operations supported
by this server.</para>
<para>If the root DSE does not have a <literal>supportedExtension</literal> attribute,
the server does not support any extended operations. For instructions on reading
the root DSE, refer to <olink type="auto-generated" targetptr="server-info-dse-info">Getting the Root DSE With Directory SDK for
Java</olink>.</para></sect1>
<sect1 id="extopts-client-side"><title>Performing an Extended Operation With &DirectorySDKForJava;</title>
<indexterm>
<primary>LDAP clients</primary>
<secondary>extended operations and</secondary>
</indexterm>
<orderedlist>
<para>To request an extended operation, do the following:</para>
<listitem><para>Construct a new <classname>LDAPExtendedOperation</classname> object,
specifying the OID of the extended operation and the data that you want applied
to the operation.</para></listitem>
<listitem><para>Invoke the <literal>extendedOperation</literal> method of
the <classname>LDAPConnection</classname> object, passing the method of the
newly constructed <classname>LDAPExtendedOperation</classname> object.</para>
</listitem>
</orderedlist>
<para>The <classname>LDAPExtendedOperation</classname> object that is returned
represents the server response. You can invoke the <literal>getID</literal> and <literal>
getValue</literal> methods of this object to get the OID and the data from
the server's response.</para></sect1>
<sect1 id="extopts-example"><title>Example Extended Operation With &DirectorySDKForJava;</title>
<para>The following example shows an LDAP client that requests an extended
operation with the OID <literal>1.2.3.4</literal> from the server.</para>
<programlisting>import netscape.ldap.*;
import java.util.*;
import java.io.*;
public class ExtOpt {
private static String OID = "1.2.3.4";
public static void main(String[] args) {
try {
UserArgs userArgs = new UserArgs("ExtOpt", args, true);
LDAPConnection ld = new LDAPConnection();
ld.connect(userArgs.getHost(), userArgs.getPort());
ld.authenticate(3, userArgs.getBindDN(),userArgs.getPassword());
System.out.println("Authenticated to directory.");
/* Create an extended operation object */
String myval = "My Value";
byte vals[] = myval.getBytes("UTF8");
LDAPExtendedOperation exop =
new LDAPExtendedOperation(OID, vals);
/* Request the extended operation from the server. */
LDAPExtendedOperation exres = ld.extendedOperation(exop);
System.out.println("Performed extended operation.");
/* Get data from the response sent by the server. */
System.out.println("OID returned: " + exres.getID());
String retValue = new String(exres.getValue(),"UTF8");
System.out.println("Value returned: " + retValue);
ld.disconnect();
}
catch(LDAPException e) {
System.out.println("Error: " + e.toString());
}
catch(UnsupportedEncodingException e) {
System.out.println("Error: UTF8 not supported");
}
}
}</programlisting>
</sect1>
</chapter>

View File

@@ -0,0 +1,545 @@
<!--
Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
Portions copyright 1999 Netscape Communications Corporation. All
Rights Reserved.
The contents of this document are subject to the terms of the
Creative Commons Attribution-ShareAlike 2.5 license or any later
version (the "License"). You may not use this document except in
compliance with the License.
See the License for the specific language governing
permissions and limitations under the License. You can obtain
a copy of the License at
http://creativecommons.org/licenses/by-sa/2.5/legalcode.
-->
<chapter id="filter-conf"><title>Using Filter Configuration Files</title>
<highlights>
<para>This chapter explains how to use API function to work with filter configuration
files. Filter configuration files can help simplify the process of selecting the appropriate
search filter for a search request. The chapter contains the following sections:</para>
<itemizedlist>
<listitem><para><olink targetptr="understanding-filter-conf">Understanding Filter
Configuration Files</olink></para></listitem>
<listitem><para><olink targetptr="understanding-filter-conf-syntax">Understanding
the Configuration File Syntax</olink></para></listitem>
<listitem><para><olink targetptr="understanding-filter-parameters">Understanding Filter
Parameters</olink></para></listitem>
<listitem><para><olink targetptr="loading-filter-conf">Loading Filter Configuration
Files</olink></para></listitem>
<listitem><para><olink targetptr="retrieving-filters">Retrieving Filters</olink></para>
</listitem>
<listitem><para><olink targetptr="filter-conf-affixes">Adding Filter Prefixes and
Suffixes</olink></para></listitem>
</itemizedlist>
</highlights>
<sect1 id="understanding-filter-conf"><title>Understanding Filter Configuration Files
</title>
<para>Suppose that you are writing a client that allows users to search the directory.
You might want to use different search filters tailored for specific types of search
criteria. For example, suppose the user wants to search for this:</para>
<literallayout><literal>bjensen@example.com</literal></literallayout>
<para>You might want to use this search filter:</para>
<literallayout><literal>(mail=bjensen@example.com)</literal></literallayout>
<para>Similarly, suppose the search term entered by the user contains numbers, like
this:</para>
<literallayout><literal>555-1212</literal></literallayout>
<para>In this case, you might want to use this search filter:</para>
<literallayout><literal>(telephoneNumber=555-1212)</literal></literallayout>
<para>Rather than write code to construct the search filter explicitly, you can generate
filters using a <firstterm>filter configuration file</firstterm>. A filter configuration
file specifies a list of filters that you can load and use in your searches.</para>
</sect1>
<sect1 id="understanding-filter-conf-syntax"><title>Understanding the Configuration
File Syntax</title>
<indexterm><primary>filter configuration files</primary><secondary>syntax</secondary>
</indexterm>
<para>A filter configuration file has the following format:</para>
<literallayout width="100"><replaceable>tag</replaceable>
<replaceable>pattern1</replaceable> <replaceable>delimiters</replaceable> <replaceable>
filter1-1</replaceable> <replaceable>desc1-1</replaceable> [<replaceable>scope1
</replaceable>]
<replaceable>filter1-2</replaceable> <replaceable>
desc1-2</replaceable> [<replaceable>scope2</replaceable>]
<replaceable>pattern2</replaceable> <replaceable>delimiters</replaceable> <replaceable>
filter2-1</replaceable> <replaceable>desc2-1</replaceable> [<replaceable>scope3
</replaceable>]
&hellip;</literallayout>
<para>Each element in the file is a string, surrounded by quotes (<literal>"</literal>).
Comments consist of lines starting with <literal>#</literal>.</para>
<para>The format supports these elements:</para>
<variablelist>
<varlistentry><term><replaceable>tag</replaceable></term>
<listitem><para>Identifies a group of filters.</para>
<para>You can use different tags to distinguish filters for different types of objects.
For example, you can use a <literal>"person"</literal> tag to identify filters for
person entries, a <literal>"organization"</literal> tag to represent filters for organization
entries, and so forth.</para>
<para>You can specify multiple tags for the same group of filters in the configuration
file using the keyword <literal>and</literal>, such as <literal>"people and organization"
</literal>.</para>
<para>You can specify a tag, or part of a tag, as a parameter. The tag narrows the
list of filters that the function retrieves.</para>
</listitem>
</varlistentry>
<varlistentry><term><replaceable>pattern</replaceable></term>
<listitem><para>Specifies a regular expression used to determine which filter is selected
based on the search criteria.</para>
<para>For example, if you specify <literal>^[0-9]</literal> as the pattern for a filter,
the filter is selected for all search criteria beginning with a number.</para>
</listitem>
</varlistentry>
<varlistentry><term><replaceable>delimiters</replaceable></term>
<listitem><para>Specify what characters separate one field from another within search
criteria.</para>
<para>For example, if the search criteria consists of a city name and state abbreviation
separated by a comma, specify <literal>","</literal> as the delimiter.</para>
</listitem>
</varlistentry>
<varlistentry><term><replaceable>filter</replaceable></term>
<listitem><para>Specifies an LDAP filter including <literal>%v</literal> to represent
the search criteria.</para>
<para>For example, to search email addresses, use the filter <literal>(mail=%v)</literal>.
During runtime, if the search criteria <literal>bjensen@example.com</literal> is entered,
the filter becomes <literal>(mail=bjensen@example.com)</literal>.</para>
<para>If the search criteria consists of a number of delimited fields such as a <replaceable>
surname</replaceable><literal>,</literal> <replaceable>first name</replaceable> format
like <literal>Jensen, Barbara</literal>, use <literal>%v1</literal>, <literal>%v2
</literal>, &hellip;, <literal>%vn</literal> to represent the fields within the search
criteria. For example:</para>
<literallayout><literal>"people"
"^[A-Z]*," "," "(&amp;(sn=%v1)(givenName=%v2))"</literal></literallayout>
<para>In the example, the delimiter is a comma. The word before the delimiter replaces <literal>
%v1</literal> in the filter, and the word after the delimiter replaces<literal>%v1
</literal>. A search for:</para>
<literallayout><literal>Jensen, Barbara</literal></literallayout><para>results in
a filter:</para>
<literallayout><literal>(&amp;(sn=Jensen)(givenName=Barbara))</literal></literallayout>
<para>You can also specify ranges of fields. For example, to specify the values in
the first three fields, use <literal>%v1-3</literal>. To specify values from the third
field to the last field, use <literal>%v3-</literal>. To specify the value in the
last field, use <literal>%v$</literal>.</para>
</listitem>
</varlistentry>
<varlistentry><term><replaceable>desc</replaceable></term>
<listitem><para>Specify short text descriptions of the filters.</para>
</listitem>
</varlistentry>
<varlistentry><term><replaceable>scope</replaceable></term>
<listitem><para>Specify the scope of each search.</para>
<para>This field is optional. It can take the values <literal>"base"</literal>, <literal>
"onelevel"</literal>, or <literal>"subtree"</literal>.</para>
</listitem>
</varlistentry>
</variablelist>
<para>For example, the following section of a filter configuration file specifies
a filter for telephone numbers and two filters for email addresses. The telephone
number filter is used if the search criteria contains one or more numbers. The email
filters are used if the search criteria contains an at sign (<literal>@</literal>).
</para>
<programlisting role="fragment">"people"
"^[0-9][0-9-]*$" " " "(telephoneNumber=*%v)" "phone number ends with"
"@" " " "(mail=%v)" "email address is"
"(mail=%v*)" "email address starts with"
</programlisting>
<para>Specify the filters in the order that you want them to be used. For example,
if you want to apply the <literal>(mail=%v)</literal> filter before the <literal>
(mail=%v*)</literal> filter, make sure that the filters appear in that order.</para>
</sect1>
<sect1 id="understanding-filter-parameters"><title>Understanding Filter Parameters
</title>
<para>Configuration file filter specifications support the following parameters:</para>
<variablelist>
<varlistentry><term><literal>%v</literal></term>
<listitem><para>Insert the search criterion verbatim in place of <literal>%v</literal>.
</para>
<para>For example, if the filter specification is <literal>(mail=%v)</literal>, entering <literal>
bjensen</literal> results in the filter <literal>(mail=bjensen)</literal>.</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>%v$</literal></term>
<listitem><para>Insert the last word of search criterion verbatim in place of <literal>
%v</literal>.</para>
<para>For example, if the filter specification is <literal>(sn=%v$)</literal>, entering <literal>
Barbara Jensen</literal> results in the filter <literal>(sn=Jensen)</literal>.</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>%v</literal><replaceable>N</replaceable></term>
<listitem><para>Insert the <replaceable>N</replaceable>th word of the criteria in
place of <literal>%v</literal>, where <replaceable>N</replaceable> is a single digit
between 1 and 9.</para>
<para>For example, if the filter specification is <literal>(sn=%v2)</literal>, entering <literal>
Barbara Jensen</literal> results in the filter <literal>(sn=Jensen)</literal>.</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>%v</literal><replaceable>M</replaceable><literal>-</literal><replaceable>
N</replaceable></term>
<listitem><para>Insert the sequence of the <replaceable>M</replaceable>th through <replaceable>
N</replaceable>th words of the criteria in place of <literal>%v</literal>, where <replaceable>
M</replaceable> and <replaceable>N</replaceable> are single digits between 1 and 9.
</para>
<para>For example, if the filter specification is <literal>(cn=%v1-2)</literal>, entering <literal>
Barbara Jensen</literal> results in the filter <literal>(cn=Barbara Jensen)</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>%v</literal><replaceable>N</replaceable><literal>-</literal></term>
<listitem><para>Insert the sequence of th e<replaceable>N</replaceable>th through
last words of the criteria in place of <literal>%v</literal>, where <replaceable>
N</replaceable> is a single digit between 1 and 9.</para>
<para>For example, if the filter specification is <literal>(cn=%v2-)</literal>, entering <literal>
Ms. Barbara Jensen</literal> results in the filter <literal>(cn=Barbara Jensen)</literal>.
</para>
</listitem>
</varlistentry>
</variablelist>
</sect1>
<sect1 id="loading-filter-conf"><title>Loading Filter Configuration Files</title>
<indexterm><primary>filter configuration files</primary><secondary>loading</secondary>
</indexterm>
<indexterm><primary>loading filter configuration files</primary></indexterm>
<para>To use a filter configuration file, you need to create an <classname>LDAPFilterDescriptor
</classname> object. The <literal>LDAPFilterDescriptor</literal> constructor allows
you to read in the filter configuration file from one of the following:</para>
<itemizedlist>
<listitem><para>A file in the local file system to which you specify the path</para>
</listitem>
<listitem><para>A file served by a web server to which you specify the URL</para>
</listitem>
<listitem><para>A location in memory where you specify a <classname>StringBuffer</classname> object
containing the configuration information</para></listitem>
</itemizedlist>
<para>The following section of code reads in a filter configuration file named <filename>
ldapfilter.conf</filename> in the current directory.</para>
<programlisting>import netscape.ldap.util.*;
&hellip;
LDAPFilterDescriptor filtdesc = null;
try {
/* Read in the filter configuration file. */
filtdesc = new LDAPFilterDescriptor("ldapfilter.conf");
} catch ( Exception e ) {
System.out.println( "Error: " + e.toString() );
}</programlisting>
</sect1>
<sect1 id="retrieving-filters"><title>Retrieving Filters</title>
<para>After loading a filter configuration file into memory, you can retrieve filters
based on the search criteria. For example, if the search criteria is an email address
such as <literal>bjensen@example.com</literal>, you can have your client automatically
search for this value in the <literal>mail</literal> attribute.</para>
<task id="retrieving-filters-task"><title>Retrieving Filters Using A Filter Configuration
File</title>
<procedure>
<step><para>Invoke the <literal>LDAPFilterDescriptor</literal> constructor to read
in the filter configuration file.</para></step>
<step><para>Invoke the <literal>getFilters</literal> method of the <classname>LDAPFilterDescriptor
</classname> object.</para><para>Specify the tag of the section that you want to use
in the filter configuration file.</para><para>You do not need to invoke the <literal>
setupFilter</literal> of the <classname>LDAPFilter</classname> object to generate
the filter. The <literal>getFilters</literal> method of the <classname>LDAPFilterDescriptor
</classname> object does this already. You just need to invoke the <literal>getFilter
</literal> method of the <classname>LDAPFilter</classname> object to get the generated
filter.</para><para>This method returns an <classname>LDAPFilterList</classname> object,
which is an enumeration of <classname>LDAPFilter</classname> objects containing the
filters for the specified search term.</para></step>
<step><para>Invoke the <literal>next</literal> method of the <classname>LDAPFilterList
</classname> object to iterate through the <classname>LDAPFilter</classname> objects.
</para></step>
<step><para>For each <classname>LDAPFilter</classname> object, get the filter by invoking
the <literal>getFilter</literal> method, passing no arguments.</para><para>To get
the total number of filter configuration lines that match the specified search term,
invoke the <literal>numFilters</literal> method of the <classname>LDAPFilterList</classname> object.
This number decrements each time you invoke the next or <literal>nextElement</literal> method.
</para></step>
</procedure>
<example id="retrieving-filters-example">
<title>Retrieving Telephone Number and Mail Filters</title>
<para>This example uses a filter configuration file, <filename>ldapfilter.conf</filename>,
with the following specifications:</para>
<programlisting role="fragment">"people"
"^[0-9][0-9-]*$" " " "(telephoneNumber=*%v)" "phone number ends with"
"@" " " "(mail=%v)" "email address is"
"(mail=%v*)" "email address starts with"</programlisting>
<para>The following code retrieves, generates, and prints filters matching the criteria:
</para>
<programlisting>String searchTerm = "bjensen@example.com";
LDAPFilterDescriptor filtdesc = null;
try {
/* Read in the filter configuration file. */
filtdesc = new LDAPFilterDescriptor("ldapfilt.conf");
/* Get filters from the section "people" */
LDAPFilterList filtlist = null;
try {
filtlist = filtdesc.getFilters("people", searchTerm);
} catch ( Exception e ) {
System.out.println("No matching tag section or filter");
System.exit(0);
}
int totalFilters = filtlist.numFilters();
System.out.println("Found " + totalFilters + " applicable filters.\n");
/* Iterate through the lines in the list. */
while ( filtlist.hasMoreElements() ) {
LDAPFilter filtline = filtlist.next();
System.out.println("Filter #" +
(totalFilters - filtlist.numFilters()));
/* Get and print information about the selected line
of filter configuration information. */
System.out.println(" Description: " + filtline.getDescription());
System.out.println(" Line #: " + filtline.getLineNumber());
System.out.println(" Matches pattern: " +
filtline.getMatchPattern());
System.out.println(" Filter template: " +
filtline.getFilterTemplate());
System.out.println(" Delimiter: " + filtline.getDelimeter());
System.out.println(" Scope: " + filtline.getScope());
/* Get the generated filter. */
String filterString = filtline.getFilter();
System.out.println(" Generated filter string: " +
filterString + "\n");
}
} catch ( Exception e ) {
System.out.println("Error: " + e.toString());
}</programlisting>
<para>When built into a program, compiled, and run, this code produces the following
output:</para>
<screen>Found 2 applicable filters.
Filter #1
Description: email address is
Line #: 3
Matches pattern: @
Filter template: (mail=%v)
Delimiter:
Scope: subtree
Generated filter string: (mail=bjensen@example.com)
Filter #2
Description: email address starts with
Line #: 4
Matches pattern: @
Filter template: (mail=%v*)
Delimiter:
Scope: subtree
Generated filter string: (mail=bjensen@example.com*)</screen>
</example>
</task>
</sect1>
<sect1 id="filter-conf-affixes"><title>Adding Filter Prefixes and Suffixes</title>
<para>If you need to apply a filter to all searches, you can add a filter prefix and
suffix to all filters rather than adding the criteria to all filters. For example,
if your client searches only for person entries, you can add the following filter
prefix to restrict the search:</para>
<literallayout><literal>(&amp;(l=Sunnyvale)</literal></literallayout>
<para>The filter prefix now requires the following suffix to balance the number of
parentheses:</para>
<literallayout><literal>)</literal></literallayout>
<para>For example, given the following filter:</para>
<literallayout><literal>(sn=Jensen)</literal></literallayout>
<para>You can use the filter prefix <literal>(&amp;(l=Sunnyvale</literal> and the
filter suffix <literal>)</literal> to narrow down the search to only the entries matching <literal>
l=Sunnyvale</literal>:</para>
<literallayout><literal>(&amp;(l=Sunnyvale)(sn=Jensen))</literal></literallayout>
<para>You can set up the filter prefix and suffix in several ways:</para>
<itemizedlist>
<listitem><para>To set these for all filters generated from the filter configuration
file, invoke the <literal>setFilterAffixes</literal> method of the <classname>LDAPFilterDescriptor
</classname> object.</para></listitem>
<listitem><para>To set the prefix or suffix for a specific filter, do one of the following:
</para>
<itemizedlist>
<listitem><para>Invoke the <literal>setFilterAffixes</literal> method of the <classname>
LDAPFilter</classname> object, then invoke the <literal>getFilter</literal> method,
passing in the search term again. This builds the filter again, using the specified
search term with the prefix and suffix.</para></listitem>
<listitem><para>Invoke the <literal>getFilter</literal> method, passing in the search
term, the prefix, and the suffix.</para></listitem>
<listitem><para>Invoke the <literal>setupFilter</literal> method, passing the search
term, the prefix, and the suffix.</para></listitem>
</itemizedlist>
<para>Setting the prefix and suffix for an individual filter overrides any prefix
or suffix set for the entire filter configuration file.</para></listitem>
</itemizedlist>
<sect2 id="affixes-all-filters"><title>Adding Affixes for All Filters</title>
<para>The following code loads a filter configuration file <filename>ldapfilter.conf
</filename> into memory, and adds the prefix <literal>(&amp;(l=Sunnyvale</literal> and
suffix <literal>)</literal> to each filter retrieved from the file:</para>
<programlisting>LDAPFilterDescriptor filtdesc = null;
try {
/* Read in the filter configuration file. */
filtdesc = new LDAPFilterDescriptor("ldapfilter.conf");
/* Add the specified prefix and suffix to all filters. */
String prefix = "(&amp;(l=Sunnyvale)";
String suffix = ")";
<emphasis>filtdesc.setFilterAffixes(prefix, suffix);</emphasis>
/* Get filters from the section "people" */
LDAPFilterList filtlist = null;
try {
filtlist = filtdesc.getFilters("people", searchTerm);
} catch (Exception e) {
System.out.println("No matching tag section or filter");
System.exit(0);
}
/* Iterate through the lines in the list. */
while (filtlist.hasMoreElements()) {
LDAPFilter filtline = filtlist.next();
/* Get and print each filter. */
String filterString = filtline.getFilter();
System.out.println(" Generated filter string: " +
filterString + "\n");
}
} catch (Exception e) {
System.out.println("Error: " + e.toString());
}</programlisting>
<para>For example, if the following search term is passed to the <literal>LDAPFilterDescriptor.getFilters
</literal> method:</para>
<literallayout><literal>bjensen@example.com</literal></literallayout>
<para>and the corresponding filter, not including the prefix or suffix, is:</para>
<literallayout><literal>(mail=bjensen@example.com)</literal></literallayout>
<para>the entire filter string retrieved by the <literal>LDAPFilter.getFilter</literal> method
is:</para>
<literallayout><literal>(&amp;(l=Sunnyvale)(mail=bjensen@example.com))</literal></literallayout>
</sect2>
<sect2 id="affixes-setFilterAffixes"><title>Adding Affixes Using <literal>setFilterAffixes
</literal></title>
<para>The following code loads a filter configuration file <filename>ldapfilter.conf
</filename> into memory, and uses the <literal>LDAPFilter.setFilterAffixes</literal> method
to add the prefix <literal>(&amp;(l=Sunnyvale</literal> and suffix <literal>)</literal> to
a generated filter:</para>
<programlisting>LDAPFilterDescriptor filtdesc = null;
try {
/* Read in the filter configuration file. */
filtdesc = new LDAPFilterDescriptor("ldapfilter.conf");
/* Get filters from the section "people" */
LDAPFilterList filtlist = null;
try {
filtlist = filtdesc.getFilters("people", searchTerm);
} catch (Exception e) {
System.out.println("No matching tag section or filter");
System.exit(0);
}
/* Iterate through the lines in the list. */
while (filtlist.hasMoreElements()) {
LDAPFilter filtline = filtlist.next();
/* Add the prefix and suffix, and generate the filter. */
String prefix = "(&amp;(l=Sunnyvale)";
String suffix = ")";
<emphasis>filtline.setFilterAffixes(prefix, suffix);</emphasis>
String filterString = filtline.getFilter(searchTerm);
System.out.println(" Generated filter string: " +
filterString + "\n");
}
} catch ( Exception e ) {
System.out.println( "Error: " + e.toString() );
}</programlisting>
<para>For example, if the following search term is passed to the <literal>LDAPFilterDescriptor.getFilters
</literal> method:</para>
<literallayout><literal>bjensen@example.com</literal></literallayout>
<para>and the corresponding filter, not including the prefix or suffix, is:</para>
<literallayout><literal>(mail=bjensen@example.com)</literal></literallayout>
<para>the entire filter string retrieved by the <literal>LDAPFilter.getFilter</literal> method
is:</para>
<literallayout><literal>(&amp;(l=Sunnyvale)(mail=bjensen@example.com))</literal></literallayout>
</sect2>
<sect2 id="affixes-getFilter"><title>Adding Affixes Using <literal>getFilter</literal></title>
<para>The following code loads a filter configuration file <filename>ldapfilter.conf
</filename> into memory, and uses the <literal>LDAPFilter.getFilter</literal> method
to add the prefix <literal>(&amp;(l=Sunnyvale</literal> and suffix <literal>)</literal> to
a generated filter:</para>
<programlisting>LDAPFilterDescriptor filtdesc = null;
try {
/* Read in the filter configuration file. */
filtdesc = new LDAPFilterDescriptor("ldapfilter.conf");
/* Get filters from the section "people" */
LDAPFilterList filtlist = null;
try {
filtlist = filtdesc.getFilters("people", searchTerm);
} catch (Exception e) {
System.out.println("No matching tag section or filter");
System.exit(0);
}
/* Iterate through the lines in the list. */
while (filtlist.hasMoreElements()) {
LDAPFilter filtline = filtlist.next();
/* Add the prefix and suffix, and generate the filter. */
String prefix = "(&amp;(l=Sunnyvale)";
String suffix = ")";
<emphasis>String filterString =
filtline.getFilter(searchTerm, prefix, suffix);</emphasis>
System.out.println(" Generated filter string: " +
filterString + "\n");
}
} catch ( Exception e ) {
System.out.println( "Error: " + e.toString() );
}</programlisting>
<para>For example, if the following search term is passed to the <literal>LDAPFilterDescriptor.getFilters
</literal> method:</para>
<literallayout><literal>bjensen@example.com</literal></literallayout>
<para>and the corresponding filter, not including the prefix or suffix, is:</para>
<literallayout><literal>(mail=bjensen@example.com)</literal></literallayout>
<para>the entire filter string retrieved by the <literal>LDAPFilter.getFilter</literal> method
is:</para>
<literallayout><literal>(&amp;(l=Sunnyvale)(mail=bjensen@example.com))</literal></literallayout>
</sect2>
<sect2 id="affixes-setupFilter"><title>Adding Affixes Using <literal>setupFilter</literal></title>
<para>The following code loads a filter configuration file <filename>ldapfilter.conf
</filename> into memory, and uses the <literal>LDAPFilter.setupFilter</literal> method
to add the prefix <literal>(&amp;(l=Sunnyvale</literal> and suffix <literal>)</literal> to
a generated filter:</para>
<programlisting>LDAPFilterDescriptor filtdesc = null;
try {
/* Read in the filter configuration file. */
filtdesc = new LDAPFilterDescriptor("ldapfilter.conf");
/* Get filters from the section "people" */
LDAPFilterList filtlist = null;
try {
filtlist = filtdesc.getFilters("people", searchTerm);
} catch (Exception e) {
System.out.println("No matching tag section or filter");
System.exit(0);
}
/* Iterate through the lines in the list. */
while (filtlist.hasMoreElements()) {
LDAPFilter filtline = filtlist.next();
/* Add the prefix and suffix, and generate the filter. */
String prefix = "(&amp;(l=Sunnyvale)";
String suffix = ")";
<emphasis>filtline.setupFilter(searchTerm, prefix, suffix);</emphasis>
String filterString = filtline.getFilter();
System.out.println(" Generated filter string: "
+ filterString + "\n");
}
} catch ( Exception e ) {
System.out.println( "Error: " + e.toString() );
}</programlisting>
<para>For example, if the following search term is passed to the <literal>LDAPFilterDescriptor.getFilters
</literal> method:</para>
<literallayout><literal>bjensen@example.com</literal></literallayout>
<para>and the corresponding filter, not including the prefix or suffix, is:</para>
<literallayout><literal>(mail=bjensen@example.com)</literal></literallayout>
<para>the entire filter string retrieved by the <literal>LDAPFilter.getFilter</literal> method
is:</para>
<literallayout><literal>(&amp;(l=Sunnyvale)(mail=bjensen@example.com))</literal></literallayout>
</sect2>
</sect1>
</chapter>

View File

@@ -0,0 +1,202 @@
<!--
Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
Portions copyright 1999 Netscape Communications Corporation. All
Rights Reserved.
The contents of this document are subject to the terms of the
Creative Commons Attribution-ShareAlike 2.5 license or any later
version (the "License"). You may not use this document except in
compliance with the License.
See the License for the specific language governing
permissions and limitations under the License. You can obtain
a copy of the License at
http://creativecommons.org/licenses/by-sa/2.5/legalcode.
-->
<chapter id="ldap-urls"><title>LDAP URLs With &DirectorySDKForJava;</title>
<highlights>
<para>This chapter describes how to use LDAP URLs to search and retrieve data
from the directory.</para>
<itemizedlist>
<para>This chapter covers the following topics:</para>
<listitem><para><olink targetptr="url-components">Getting the Components of
an LDAP URL With Directory SDK for Java</olink></para></listitem>
<listitem><para><olink targetptr="url-processing">Processing an LDAP URL With
Directory SDK for Java</olink></para></listitem>
<listitem><para><olink targetptr="url-search-example">Searching Using an LDAP
URL With Directory SDK for Java</olink></para></listitem>
</itemizedlist>
</highlights>
<sect1 id="url-components"><title>Getting the Components of an LDAP URL With &DirectorySDKForJava;</title>
<itemizedlist>
<para>To get the individual components of an LDAP URL, pass the URL to the <literal>
LDAPUrl</literal> constructor to create a new <classname>LDAPUrl</classname> object.
Then, use the following methods:</para>
<listitem><para>To get an array of the attributes that should be returned
in the search results, use the <literal>getAttributeArray</literal> method.
To get these attributes as an enumeration, use the <literal>getAttributes</literal> method.
</para></listitem>
<listitem><para>To get the host name of the LDAP server, use the <literal>getHost
</literal> method.</para></listitem>
<listitem><para>To get the port number of the LDAP server, use the <literal>getPort
</literal> method.</para></listitem>
<listitem><para>To get the base DN, use the <literal>getDN</literal> method.</para>
</listitem>
<listitem><para>To get the scope of the search, use the <literal>getScope</literal> method.
</para></listitem>
<listitem><para>To get the search filter, use the <literal>getFilter</literal> method.
</para></listitem>
</itemizedlist>
</sect1>
<sect1 id="url-processing"><title>Processing an LDAP URL With &DirectorySDKForJava;</title>
<itemizedlist>
<para>To process the search request specified by an LDAP URL, you can invoke
one of the following methods, passing in the <classname>LDAPUrl</classname> object:
</para>
<listitem><para>If the URL specifies a base search for a single entry, invoke
the <literal>read</literal> method of the <classname>LDAPConnection</classname> object.
This method reads the entry from the directory.</para></listitem>
<listitem><para>Otherwise, invoke the <literal>search</literal> method of
the <classname>LDAPConnection</classname> object to perform the search.</para>
</listitem>
</itemizedlist>
<para>Both methods create a new <classname>LDAPConnection</classname> object
and connect to the LDAP server specified in the URL. Next, the methods perform
the search. Then the methods disconnect.</para></sect1>
<sect1 id="url-search-example"><title>Searching Using an LDAP URL With &DirectorySDKForJava;</title>
<para>The following example demonstrates a search that uses an LDAP URL, invoking
the <literal>search</literal> method of the <classname>LDAPConnection</classname> object
to perform the search. Before the search is performed, the LDAP URL is exploded
using the methods suggested previously in this chapter.</para>
<programlisting>import netscape.ldap.*;
import netscape.ldap.util.*;
import java.net.MalformedURLException;
import java.util.*;
public class SrchUrl {
public static void main( String[] args ) {
LDAPConnection ld = null;
LDAPEntry findEntry = null;
int status = -1;
try {
UserArgs userArgs = new UserArgs("SrchUrl", args, false);
ld = new LDAPConnection();
ld.connect(userArgs.getHost(), userArgs.getPort());
LDAPUrl myUrl = new LDAPUrl(
"ldap://" +
userArgs.getHost() + // server host
":" +
userArgs.getPort() + // server port
"/" +
"dc=example,dc=com" + // base DN
"?" +
"cn,sn,mail,telephonenumber" + // attrs to retrieve
"?" +
"sub" + // search scope
"?" +
"(uid=bjensen)"); // search filter
System.out.println( "LDAP URL : " + myUrl.toString() );
System.out.println( " host : " + myUrl.getHost() );
System.out.println( " port : " + myUrl.getPort() );
System.out.println( " baseDN: " + myUrl.getDN() );
String [] myAttrs = myUrl.getAttributeArray();
for ( String myAttr: myAttrs ) {
System.out.println( " attrs : " + myAttr );
}
System.out.println( " scope : " + myUrl.getScope() );
System.out.println( " filter: " + myUrl.getFilter() );
LDAPSearchResults res = ld.search( myUrl );
/* Loop on results until finished; will only be one! */
while ( res.hasMoreElements() ) {
/* Next directory entry, really only one at most */
try {
findEntry = res.next();
} catch ( LDAPReferralException e ) {
System.out.println( "Search reference: " );
LDAPUrl refUrls[] = e.getURLs();
for (int i=0; i&lt;refUrls.length; i++) {
System.out.println( "\t" + refUrls[i].getUrl() );
}
continue;
} catch ( LDAPException e ) {
System.err.println( "Error: " + e.toString() );
continue;
}
/* Get the attributes of the entry */
LDAPAttributeSet findAttrs = findEntry.getAttributeSet();
Enumeration enumAttrs = findAttrs.getAttributes();
/* Loop on attributes */
while ( enumAttrs.hasMoreElements() ) {
LDAPAttribute anAttr =
(LDAPAttribute)enumAttrs.nextElement();
String attrName = anAttr.getName();
if ( attrName.equals( "cn" ) )
System.out.println( "Full name:" );
else if ( attrName.equals( "sn" ) )
System.out.println( "Last name (surname):" );
else if ( attrName.equals( "mail" ) )
System.out.println( "Email address:" );
else if ( attrName.equals( "telephonenumber" ) )
System.out.println( "Telephone number:" );
/* Loop on values for this attribute */
Enumeration enumVals = anAttr.getStringValues();
if (enumVals != null) {
while ( enumVals.hasMoreElements() ) {
String aVal = ( String )enumVals.nextElement();
System.out.println( "\t" + aVal );
}
}
}
}
}
catch( LDAPException e ) {
System.err.println( "Error: " + e.toString() );
}
catch( MalformedURLException e ) {
System.err.println( "Error: " + e.toString() );
}
/* Done, so disconnect */
if ( (ld != null) &amp;&amp; ld.isConnected() ) {
try {
ld.disconnect();
} catch ( LDAPException e ) {
System.out.println( "Error: " + e.toString() );
}
}
System.exit(status);
}
}</programlisting>
<para>When this program is compiled and run against a directory that holds
Barbara Jensen's entry, the program generates the following output.</para>
<screen>$ <userinput>java SrchUrl -h myhost -p 1389</userinput>
LDAP URL : ldap://myhost:1389/dc=example,dc=com?cn,sn,mail,telephonenumber?sub?(uid=bjensen)
host : mykryten
port : 1389
baseDN: dc=example,dc=com
attrs : cn
attrs : sn
attrs : mail
attrs : telephonenumber
scope : 2
filter: (uid=bjensen)
Full name:
Barbara Jensen
Babs Jensen
Last name (surname):
Jensen
Email address:
bjensen@example.com
Telephone number:
+1 408 555 1862</screen>
</sect1>
</chapter>

View File

@@ -0,0 +1,212 @@
<!--
Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
Portions copyright 1999 Netscape Communications Corporation. All
Rights Reserved.
The contents of this document are subject to the terms of the
Creative Commons Attribution-ShareAlike 2.5 license or any later
version (the "License"). You may not use this document except in
compliance with the License.
See the License for the specific language governing
permissions and limitations under the License. You can obtain
a copy of the License at
http://creativecommons.org/licenses/by-sa/2.5/legalcode.
-->
<chapter id="quickstart-jdk"><title>Getting Started With &DirectorySDKForJava;</title>
<highlights>
<para>This chapter shows how to develop a first LDAP client with the &DirectorySDKForJava;.
</para>
<itemizedlist>
<para>This chapter covers the following topics:</para>
<listitem><para><olink targetptr="understanding-java-classes">Understanding
the LDAP Java Classes</olink></para></listitem>
<listitem><para><olink targetptr="understanding-sample">Understanding the
Sample Java Client</olink></para></listitem>
<listitem><para><olink targetptr="sample-code">Sample Java Code</olink></para>
</listitem>
</itemizedlist>
</highlights>
<sect1 id="understanding-java-classes"><title>Understanding the LDAP Java
Classes</title>
<indexterm>
<primary>packages</primary>
<secondary>summary of</secondary>
</indexterm><indexterm>
<primary>&DirectorySDKForJava;</primary>
<secondary>packages</secondary>
</indexterm>
<para>&DirectorySDKForJava; includes the LDAP Java classes, which you use
to build LDAP clients. The LDAP Java classes allow you to write client applications
that connect to LDAP servers. The classes also allow you to perform standard
LDAP operations. For example, you can search for entries. You can also add,
update, or delete entries.</para>
<para>The classes are organized in the following packages.</para>
<variablelist>
<varlistentry><term><literal>com.netscape.sasl</literal></term>
<listitem><para>Contains the interfaces and classes that you can use to enable
your client to authenticate by using a SASL mechanism.</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>com.netscape.sasl.mechanisms</literal></term>
<listitem><para>Contains an implementation of the <literal>EXTERNAL</literal> SASL
mechanism driver.</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>netscape.ldap</literal></term>
<listitem><para>Contains the main LDAP Java classes, including classes that
allow you to connect to an LDAP server, manipulate entries and attributes,
and retrieve search results.</para>
</listitem>
</varlistentry>
<!--<varlistentry><term><literal>netscape.ldap.beans</literal></term>
<listitem><para>Contains LDAP <trademark>JavaBeans
</trademark> technology. You can use LDAP JavaBeans
classes in a development environment such as Sun Java
Studio.</para>
</listitem>
</varlistentry>-->
<varlistentry><term><literal>netscape.ldap.ber.stream</literal></term>
<listitem><para>Contains the LDAP Java classes that implement the <firstterm>Basic
Encoding Rules</firstterm> (BER) for transfer syntax. For more information
about BER, see ISO-IEC 8825 at <ulink url="http://www.iso.ch/" type="url">http://www.iso.ch/
</ulink>.</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>netscape.ldap.controls</literal></term>
<listitem><para>Contains the LDAP Java classes that implement specific LDAP
v3 controls. The implementations include controls to request server-side sorting
and persistent searches.</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>netscape.ldap.factory</literal></term>
<listitem><para>Contains classes that allow you to create an SSL socket connection
to a server.</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>netscape.ldap.util</literal></term>
<listitem><para>Contains utility classes, such as classes to parse LDIF data
and filters that allow regular expression matching.</para>
</listitem>
</varlistentry>
</variablelist>
<para>Clients typically execute methods in &DirectorySDKForJava; synchronously.
All LDAP operations block until the operations are completed, except for the <literal>
search</literal> method, which can return information before all the results
have been received.</para>
<para>An asynchronous interface is also provided for circumstances that require
low-level interaction with an LDAP server. The asynchronous interface is discussed
more fully in <olink targetptr="asynchronous">Chapter&nbsp;13, Writing Asynchronous Clients With Directory SDK for Java</olink>.</para></sect1>
<sect1 id="understanding-sample"><title>Understanding the Sample Java Client</title>
<para>The sample client in this chapter retrieves the full name (<literal>cn</literal>),
last name (<literal>sn</literal>), email address (<literal>mail</literal>),
and telephone number (<literal>telephoneNumber</literal>) of Barbara Jensen.
You can find the program in the <filename>GetAttrs.java</filename> file in
the <filename class="directory">examples/java</filename> directory.</para>
<orderedlist>
<para>The client does the following:</para>
<listitem><para>Creates a new <classname>LDAPConnection</classname> object,
which represents the connection to the LDAP server</para></listitem>
<listitem><para>Connects to the server</para></listitem>
<listitem><para>Searches for a single entry, identified by the DN using the
following search criteria:</para>
<itemizedlist>
<listitem><para>The base DN, the starting point for the search, is <literal>uid=bjensen,ou=People,dc=example,dc=com
</literal>.</para></listitem>
<listitem><para>The search scope is <literal>LDAPConnection.SCOPE_BASE</literal>,
meaning only the base DN.</para></listitem>
<listitem><para>The search filter is <literal>"objectclass=*"</literal>, meaning
the filter matches any entry.</para><para>As the scope narrows the search
to a single entry, the search filter does not need to be more specific. </para>
</listitem>
</itemizedlist>
<para>To invoke a search on a single entry with these parameters is equivalent
to using the <literal>LDAPConnection.read</literal> method.</para>
</listitem>
<listitem><para>Iterates through the enumerated search results to retrieve
and print the values of the <literal>cn</literal>, <literal>sn</literal>, <literal>
mail</literal>, and <literal>telephoneNumber</literal> attributes</para><para>This
iteration also allows the client to obtain multiple values for a single attribute.
</para></listitem>
<listitem><para>Disconnects from the server</para></listitem></orderedlist>
<para>Before you compile the sample client, make sure that the <filename>packages/ldapjdk.jar
</filename> file is in your <envar>CLASSPATH</envar>.</para></sect1>
<sect1 id="sample-code"><title>Sample Java Code</title>
<programlisting>import netscape.ldap.*;
import netscape.ldap.util.*;
import java.util.*;
public class GetAttrs {
public static void main( String[] args ) {
try {
UserArgs userArgs = new UserArgs("GetAttrs", args, false);
LDAPConnection ld = new LDAPConnection();
ld.connect(userArgs.getHost(), userArgs.getPort());
String ENTRYDN = "uid=bjensen, ou=People, dc=example,dc=com";
String[] attrNames = {
"cn", // Get canonical name(s) (full name)
"sn", // Get surname(s) (last name)
"mail", // Get email address(es)
"telephonenumber"}; // Get telephone number(s)
LDAPSearchResults res =
ld.search(ENTRYDN, ld.SCOPE_BASE, "(objectclass=*)",
attrNames, false );
/* Loop on results until finished; only one entry here */
while (res.hasMoreElements()) {
LDAPEntry findEntry = null;
try {
findEntry = res.next();
} catch (LDAPReferralException e) {
System.out.println("Search reference: ");
LDAPUrl refUrls[] = e.getURLs();
for (int i=0; i &lt; refUrls.length; i++) {
System.out.println("\t" + refUrls[i].getUrl());
}
continue;
} catch (LDAPException e) {
System.out.println("Error: " + e.toString());
continue;
}
/* Get the attributes of the entry */
LDAPAttributeSet findAttrs = findEntry.getAttributeSet();
Enumeration enumAttrs = findAttrs.getAttributes();
/* Loop on attributes */
while (enumAttrs.hasMoreElements()) {
LDAPAttribute anAttr =
(LDAPAttribute)enumAttrs.nextElement();
String attrName = anAttr.getName();
if (attrName.equals("cn")) {
System.out.println("Full name:");
} else if (attrName.equals("sn")) {
System.out.println("Last name (surname):");
} else if (attrName.equals("mail")) {
System.out.println("Email address:");
} else if (attrName.equals("telephonenumber")) {
System.out.println("Telephone number:");
}
/* Loop on values for this attribute */
Enumeration enumVals = anAttr.getStringValues();
if (enumVals != null) {
while (enumVals.hasMoreElements()) {
String aVal = (String)enumVals.nextElement();
System.out.println("\t" + aVal);
}
}
}
}
ld.disconnect();
}
catch(LDAPException e) {
System.out.println("Error: " + e.toString());
}
}
}</programlisting>
</sect1>
</chapter>

View File

@@ -0,0 +1,338 @@
<!--
Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
Portions copyright 1999 Netscape Communications Corporation. All
Rights Reserved.
The contents of this document are subject to the terms of the
Creative Commons Attribution-ShareAlike 2.5 license or any later
version (the "License"). You may not use this document except in
compliance with the License.
See the License for the specific language governing
permissions and limitations under the License. You can obtain
a copy of the License at
http://creativecommons.org/licenses/by-sa/2.5/legalcode.
-->
<chapter id="sasl"><title>SASL Authentication With &DirectorySDKForJava;</title>
<highlights>
<para>This chapter describes the process of using a SASL mechanism to authenticate
an LDAP client to an LDAP server.</para>
<itemizedlist>
<para>This chapter covers the following topics:</para>
<listitem><para><olink targetptr="sasl-overview">Understanding SASL and Directory
SDK for Java</olink></para></listitem>
<listitem><para><olink targetptr="sasl-prepare">Preparing to Use SASL Authentication
With Directory SDK for Java</olink></para></listitem>
<listitem><para><olink targetptr="sasl-client">Using SASL in the Client With
Directory SDK for Java</olink></para></listitem>
<listitem><para><olink targetptr="sasl-reading">Further Reading About SASL</olink></para>
</listitem>
</itemizedlist>
</highlights>
<sect1 id="sasl-overview"><title>Understanding SASL and &DirectorySDKForJava;</title>
<indexterm>
<primary>SASL</primary>
<secondary>defined</secondary>
</indexterm>
<para>The Simple Authentication and Security Layer (SASL) is an authentication
method. SASL allows you to use mechanisms other than simple passwords and
SSL for authenticating over connection-based protocols, such as LDAP.</para>
<para>All SASL mechanisms are registered with the Internet Assigned Numbers
Authority (IANA). Included among these mechanisms are <literal>KERBEROS_V4</literal>, <literal>
GSSAPI</literal>, and several others. The client implements these mechanisms
through the use of mechanism drivers. These drivers are classes that contain
the code that is required for authenticating over a given mechanism.</para>
<para>When a client attempts to authenticate to an LDAP server with the <literal>
LDAPConnection.authenticate</literal> method, the client can specify a list
of SASL mechanisms to use. If the client does not specify any mechanisms, &DirectorySDKForJava; queries
the server to find out which mechanisms the server supports. If &DirectorySDKForJava; and
the server have a common mechanism, authentication can occur.</para>
<para>If the server supports a requested mechanism, the server responds with
one or more challenges. To authenticate, the client must correctly respond
to these challenges. Client handling is performed transparently by &DirectorySDKForJava; with
a mechanism driver.</para>
<para>If the server does not support any of the requested mechanisms, the
SDK returns an <classname>AuthenticationNotSupportedException</classname>.</para>
<para>If the mechanism driver requires additional authentication data from
the client, the driver sends a <classname>Callback</classname> object to the
client. To prepare for the callback, the client implements a <classname>CallbackHandler
</classname> and passes the handler to &DirectorySDKForJava;. The SASL
mechanism might need additional client credentials. The SASL mechanism might
also notify the client of errors during the SASL negotiations. For either
purpose, the mechanism calls the <classname>CallbackHandler</classname> object
with <classname>Callback</classname> objects for each item to be processed.
The <classname>CallbackHandler</classname> then determines how to proceed.</para>
<para>&DirectorySDKForJava; includes a package, <literal>com.netscape.sasl</literal>,
that contains the code necessary to perform all of the steps involved in SASL
authentication.</para></sect1>
<sect1 id="sasl-prepare"><title>Preparing to Use SASL Authentication With &DirectorySDKForJava;</title>
<itemizedlist>
<para>Before performing SASL authentication, you must do the following:</para>
<listitem><para>Ensure that your LDAP server supports at least one SASL mechanism
</para></listitem>
<listitem><para>Ensure that your client environment supports at least one
SASL mechanism supported by the server</para></listitem>
</itemizedlist>
<sect2 id="sasl-prepare-server"><title>SASL Support on the Server</title>
<indexterm>
<primary>SASL</primary>
<secondary>server-side requirements</secondary>
</indexterm>
<para>&cnDirectoryServer; supports a plug-in API that allows you to write
your own server plug-in to handle SASL authentication. &cnDirectoryServer; also
supports SASL authentication through DIGEST-MD5 and through GSSAPI.</para>
<itemizedlist>
<para>If you write your own plug-in, your plug-in uses a registered SASL mechanism
to do the following:</para>
<listitem><para>Get information from a SASL bind request.</para></listitem>
<listitem><para>Create and send a SASL bind response back to the client.</para>
<para>This response can take the form of a challenge that requires an answer
from the client. The response can also take the form of an error message.
Finally, the response can take the form of a success message indicating that
authentication is complete.</para></listitem>
</itemizedlist>
</sect2>
<sect2 id="sasl-prepare-client"><title>SASL Support on the Client</title>
<indexterm>
<primary>SASL</primary>
<secondary>client-side requirements</secondary>
</indexterm>
<para>To authenticate over SASL, you must have a mechanism in your SASL client
package. If you have obtained a <classname>ClientFactory</classname> class
that can produce a SASL mechanism that your server supports, you can name
its package in your code.</para>
<itemizedlist>
<para>This option can be performed in one of two ways:</para>
<listitem><para>Request a SASL client. Specify the package in the <property>javax.security.sasl.client.pkgs
</property> property of its <classname>Hashtable</classname>.</para></listitem>
<listitem><para>Set the package as the default factory for the session with
the <literal>Sasl.setSaslClientFactory</literal> method.</para></listitem>
</itemizedlist>
<para>For example, you might have a class, <classname>mysecurity.sasl.ClientFactory
</classname>, capable of producing a <classname>SaslClient</classname> object
for one or more mechanisms. You could then write either of the two following
bits of code:</para>
<programlisting>Hashtable props = new Hashtable();
props.put("javax.security.sasl.client.pkgs", "mysecurity.sasl");
ld.authenticate(dn, props, cbh);</programlisting>
<programlisting>Sasl.setSaslClientFactory (new mysecurity.sasl.ClientFactory());
ld.authenticate(dn, props, cbh);</programlisting>
<para>The parameters used have the following descriptions:</para>
<variablelist>
<varlistentry><term><parameter>dn</parameter></term>
<listitem><para>Authentication DN</para>
</listitem>
</varlistentry>
<varlistentry><term><parameter>props</parameter></term>
<listitem><para>Optional properties that the mechanism accepts</para>
<para>Refer to <olink type="auto-generated" targetptr="sasl-client-external">Using
the External Mechanism</olink> for details.</para>
</listitem>
</varlistentry>
<varlistentry><term><parameter>cbh</parameter></term>
<listitem><para>Instance of <classname>CallbackHandler</classname> that is
implemented in your application</para>
</listitem>
</varlistentry>
</variablelist>
</sect2>
<sect2 id="sasl-prepare-callback"><title>Implementing <literal>javax.security.auth.callback
</literal></title>
<indexterm>
<primary>authentication</primary>
<secondary>implementing SASL callbacks</secondary>
</indexterm><indexterm>
<primary>callbacks</primary>
<secondary>implementing for SASL</secondary>
</indexterm><indexterm>
<primary>SASL</primary>
<secondary>implementing callbacks</secondary>
</indexterm>
<para>Some SASL mechanisms require additional credentials during the authentication
process. To provide this additional information, your SASL client might need
to implement <classname>Callback</classname> objects and a <classname>CallbackHandler
</classname> to list credentials. <classname>Callback</classname> and <classname>
CallbackHandler</classname> are part of the <literal>javax.security.auth.callback
</literal> package.</para>
<para>The following example shows <classname>Callback</classname> and <classname>
CallbackHandler</classname> implementations.</para>
<programlisting>class SampleCallbackHandler implements CallbackHandler {
SampleCallbackHandler(String userName) {
userName = userName;
}
/** Invoke the requested Callback */
public void invokeCallback(Callback[] callbacks)
throws java.io.IOException,UnsupportedCallbackException {
for (int i = 0; i &lt; callbacks.length; i++) {
if (callbacks[i] instanceof TextOutputCallback) {
// display the message according to the
// specified STYLE
TextOutputCallback toc =
&#9;&#9; (TextOutputCallback)callbacks[i];
switch (toc.getStyle()) {
case TextOutputCallback.ERROR:
System.out.println("ERROR: " + toc.getMessage());
break;
case TextOutputCallback.INFORMATION:
System.out.println(toc.getMessage());
break;
case TextOutputCallback.WARNING:
System.out.println("WARNING: " + toc.getMessage());
break;
}
} else if (callbacks[i] instanceof TextInputCallback){
// prompt the user for information
TextInputCallback tic = (TextInputCallback)callbacks[i];
// display the prompt and a default reply
System.err.print(tic.getPrompt() + " [" +
tic.getDefaultText() + "]: ");
System.err.flush();
BufferedReader reader = new
BufferedReader(new InputStreamReader(System.in));
tic.setText(reader.readLine());
} else if (callbacks[i] instanceof NameCallback) {
((NameCallback)callbacks[i]).setName(_userName);
} else if (callbacks[i] instanceof PasswordCallback){
// prompt the user for sensitive information
PasswordCallback pc = (PasswordCallback)callbacks[i];
System.err.print(pc.getPrompt() + " ");
System.err.flush();
pc.setPassword(readPassword(System.in));
} else if (callbacks[i] instanceof LanguageCallback){
// Get the language from the locale
LanguageCallback lc = (LanguageCallback)callbacks[i];
lc.setLocale(Locale.getDefault());
} else {
throw new UnsupportedCallbackException(
&#9;&#9; callbacks[i], "Unrecognized Callback");
}
}
}
/** Reads user password from given input stream. */
private char[] readPassword(InputStream in) {
// insert code to read a user password from the
// input stream
}
private String _userName = null;
}</programlisting>
</sect2>
</sect1>
<sect1 id="sasl-client"><title>Using SASL in the Client With &DirectorySDKForJava;</title>
<itemizedlist>
<para>You are ready to authenticate when you have done the following:</para>
<listitem><para>Determined that at least one SASL mechanism exists in common
between the server and your client environment</para></listitem>
<listitem><para>Implemented <classname>javax.security.auth.callback.CallbackHandler
</classname> if you might need to supply additional credentials during authentication
</para></listitem>
</itemizedlist>
<para>The following example shows how to use SASL in an application:</para>
<programlisting>Hashtable props = new Hashtable();
props.put("javax.security.sasl.client.pkgs", "mysecurity.sasl");
ld.authenticate(dn, props, new SampleCallbackHandler());</programlisting>
<sect2 id="sasl-client-external"><title>Using the <literal>External</literal> Mechanism
</title>
<indexterm>
<primary>SASL</primary>
<secondary>using the EXTERNAL mechanism with</secondary>
</indexterm><indexterm>
<primary>SSL</primary>
<secondary>using SASL with</secondary>
</indexterm>
<para>&DirectorySDKForJava; includes a mechanism called <literal>EXTERNAL</literal>.
This mechanism verifies that SSL authentication has already completed before
the mechanism allows a client to connect over LDAP.</para>
<orderedlist>
<para>To use the <literal>EXTERNAL</literal> mechanism, do the following:</para>
<listitem><para>Bind to the server, and authenticate using SSL.</para><para>Refer
to <olink type="auto-generated" targetptr="ssl-connecting">Connecting to a
Server Over SSL With Directory SDK for Java</olink> for details.</para>
</listitem>
<listitem><para>Call the <literal>LDAPConnection.authenticate</literal> method
as follows:</para>
<programlisting>ld = new LDAPConnection();
ld.authenticate(
null, new String[]{"EXTERNAL"}, null, (CallbackHandler)null);</programlisting>
<para><literal>LDAPConnection.authenticate</literal> takes the following parameters.
</para>
<variablelist>
<varlistentry><term><parameter>dn</parameter></term>
<listitem><para>Authentication DN</para>
</listitem>
</varlistentry>
<varlistentry><term><parameter>mechanisms</parameter></term>
<listitem><para>List of SASL mechanisms to use for authentication</para>
<para>If <literal>null</literal> is specified, &DirectorySDKForJava; queries
the server for all available mechanisms.</para>
</listitem>
</varlistentry>
<varlistentry><term><parameter>props</parameter></term>
<listitem><para>Optional properties that the mechanism accepts, which include
the following:</para>
<variablelist>
<varlistentry><term><property>javax.security.sasl.encryption.minimum</property></term>
<listitem><para>The minimum key length to be used during the session.</para>
<para>The default value is <literal>0</literal>, no session protection. A
value of <literal>1</literal> enables integrity protection only.</para>
</listitem>
</varlistentry>
<varlistentry><term><property>javax.security.sasl.encryption.maximum</property></term>
<listitem><para>The maximum key length to be used during the session.</para>
<para>The default value is <literal>256</literal>.</para>
</listitem>
</varlistentry>
<varlistentry><term><property>javax.security.sasl.server.authentication</property></term>
<listitem><para>A boolean value.</para>
<para><literal>true</literal> if a server must authenticate to the client.
The default value is <literal>false</literal>.</para>
</listitem>
</varlistentry>
<varlistentry><term><property>javax.security.sasl.ip.local</property></term>
<listitem><para>The client's IP address in dotted decimal format.</para>
<para>This value is required for <literal>KERBEROS_V4</literal> authentication.
No default value exists.</para>
</listitem>
</varlistentry>
<varlistentry><term><property>javax.security.sasl.ip.remote</property></term>
<listitem><para>The server's IP address in dotted decimal format.</para>
<para>This value is required for <literal>KERBEROS_V4</literal> authentication.
No default value exists.</para>
</listitem>
</varlistentry>
<varlistentry><term><property>javax.security.sasl.maxbuffer</property></term>
<listitem><para>The maximum size of the security layer frames.</para>
<para>The default is <literal>0</literal>, meaning that the client does not
use the security layer.</para>
</listitem>
</varlistentry>
<varlistentry><term><property>javax.security.sasl.client.pkgs</property></term>
<listitem><para>A bar-separated list of package names to use when locating
a <classname>SaslClientFactory</classname>.</para>
</listitem>
</varlistentry>
</variablelist>
</listitem>
</varlistentry>
<varlistentry><term><parameter>cbh</parameter></term>
<listitem><para>Instance of <classname>CallbackHandler</classname> that is
implemented in your application.</para>
</listitem>
</varlistentry>
</variablelist>
</listitem>
</orderedlist>
</sect2>
<sect2 id="sasl-client-other"><title>Other SASL Mechanisms</title>
<para>Authentication with a SASL mechanism other than <literal>EXTERNAL</literal> requires
you to implement classes for the mechanism in the client and on the server.</para>
</sect2>
</sect1>
<sect1 id="sasl-reading"><title>Further Reading About SASL</title>
<para>SASL is described in <ulink url="http://www.ietf.org/rfc/rfc4422.txt"
type="text_url">RFC 4422</ulink>.</para>
<para>For a current list of registered SASL mechanisms, see <ulink
url="http://www.iana.org/assignments/sasl-mechanisms" type="url">http://www.iana.org/assignments/sasl-mechanisms
</ulink>.</para></sect1>
</chapter>

View File

@@ -0,0 +1,970 @@
<!--
Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
Portions copyright 1999 Netscape Communications Corporation. All
Rights Reserved.
The contents of this document are subject to the terms of the
Creative Commons Attribution-ShareAlike 2.5 license or any later
version (the "License"). You may not use this document except in
compliance with the License.
See the License for the specific language governing
permissions and limitations under the License. You can obtain
a copy of the License at
http://creativecommons.org/licenses/by-sa/2.5/legalcode.
-->
<chapter id="searching"><title>Searching the Directory With &DirectorySDKForJava;</title>
<highlights>
<para>This chapter explains how to use the LDAP Java classes to search the
directory to retrieve entries. The chapter also describes how to get attributes
and attribute values from an entry.</para>
<itemizedlist>
<para>This chapter covers the following topics:</para>
<listitem><para><olink targetptr="searching-overview">Searching With the LDAP
Java Classes</olink></para></listitem>
<listitem><para><olink targetptr="searching-request">Sending a Search Request
With Directory SDK for Java</olink></para></listitem>
<listitem><para><olink targetptr="searching-results">Getting the Search Results
With Directory SDK for Java</olink></para></listitem>
<listitem><para><olink targetptr="searching-sorting">Sorting the Search Results
With Directory SDK for Java</olink></para></listitem>
<listitem><para><olink targetptr="searching-abandoning">Abandoning a Search
With Directory SDK for Java</olink></para></listitem>
<listitem><para><olink targetptr="searching-example">Searching the Directory
With Directory SDK for Java</olink></para></listitem>
<listitem><para><olink targetptr="searching-read">Reading an Entry With Directory
SDK for Java</olink></para></listitem>
<listitem><para><olink targetptr="searching-child-entries">Listing Child Entries
With Directory SDK for Java</olink></para></listitem>
</itemizedlist>
</highlights>
<sect1 id="searching-overview"><title>Searching With the LDAP Java Classes</title>
<itemizedlist>
<para>In &DirectorySDKForJava;, searches are represented by objects of
the following classes:</para>
<listitem><para>You can send a search request by invoking the <literal>search</literal> method
of the <classname>LDAPConnection</classname> object.</para></listitem>
<listitem><para>You can specify a set of search constraints by using an <classname>
LDAPSearchConstraints</classname> object. The constraints can specify the
maximum number of results to return. The constraints can also specify the
maximum amount of time that is allowed for a search.</para></listitem>
<listitem><para>You can specify different parts of the search criteria in
separate arguments. Alternatively, you can construct an <classname>LDAPUrl</classname> object
to specify the search criteria.</para></listitem>
<listitem><para>You can search for a single entry by invoking the <literal>read</literal> method
of the <classname>LDAPConnection</classname> object.</para></listitem>
<listitem><para>The server returns the search results to the LDAP Java classes,
which represents the results as an <classname>LDAPSearchResults</classname> object.
</para></listitem>
</itemizedlist>
</sect1>
<sect1 id="searching-request"><title>Sending a Search Request With &DirectorySDKForJava;</title>
<para>To search the directory, use the <literal>search</literal> method of
the <classname>LDAPConnection</classname> object. The search results are returned
in the form of an <classname>LDAPSearchResults</classname> object.</para>
<programlisting>public LDAPSearchResults search(String base, int scope,
&nbsp;&nbsp;&nbsp;&nbsp;String filter, String attrs[], boolean attrsOnly,
&nbsp;&nbsp;&nbsp;&nbsp;LDAPSearchConstraints cons) throws LDAPException</programlisting>
<para>You need to specify the following parameters as arguments to the <literal>search
</literal> method.</para>
<variablelist>
<varlistentry><term><parameter>base</parameter></term>
<listitem><para>Specifies the base DN, which is the entry on and under which
the search is carried out.</para>
<para>For example, when searching entries with DNs such as <literal>uid=bjensen,ou=People,dc=example,dc=com
</literal>, the <parameter>base</parameter> could be <literal>ou=People,dc=example,dc=com
</literal> or <literal>dc=example,dc=com</literal>.</para>
</listitem>
</varlistentry>
<varlistentry><term><parameter>scope</parameter></term>
<listitem><para>Specifies the scope of the search.</para>
<para>You can adjust the scope of the search to examine only the entry identified
by the <parameter>base</parameter>, only those entries one level down the
tree from the <parameter>base</parameter>, or the entire subtree underneath
the <parameter>base</parameter>.</para>
</listitem>
</varlistentry>
<varlistentry><term><parameter>filter</parameter></term>
<listitem><para>Specifies what to search for.</para>
<para>A search filter specifies what search results to return. The filter
meaning can be simple, such as &ldquo;find entries where the last name is
Jensen&rdquo;. The filter meaning can also be complex, such as &ldquo;find
entries that belong to Dept. #17 and with first names that start with the
letter F.&rdquo;</para>
</listitem>
</varlistentry>
<varlistentry><term><parameter>attrs</parameter></term><term><parameter>attrsOnly
</parameter></term>
<listitem><para>Specify the entry attributes to retrieve.</para>
<para>For example, you can use <parameter>attrs</parameter> to retrieve only
email addresses and phone numbers. Alternatively, you can set up a search
to return all attributes in an entry. You can also specify to return only
the names of attributes, not the values, by setting <parameter>attrsOnly</parameter> to <constant>
true</constant>.</para>
</listitem>
</varlistentry>
<varlistentry><term><parameter>cons</parameter></term>
<listitem><para>Specifies constraints to apply to the search when you do not
want to use the default constraints.</para>
</listitem>
</varlistentry>
</variablelist>
<para>The following figure illustrates how search criteria work.</para>
<figure id="searching-criteria"><title>Criteria for an LDAP Search</title>
<mediaobject>
<imageobject><imagedata entityref="hierovrw"></imageobject>
<textobject><simpara>How search criteria work</simpara></textobject>
</mediaobject>
</figure>
<para>You can also specify the criteria in the form of an LDAP URL. An LDAP
URL allows you to specify the host name and port number of the LDAP server
that you want to search. To search a different LDAP server than the server
you are connected to, you can invoke the search method. You then specify an
LDAP URL in the form of an <classname>LDAPUrl</classname> object. See <olink
targetptr="ldap-urls">Chapter&nbsp;7, LDAP URLs With Directory SDK for Java</olink> for
details.</para>
<sect2 id="searching-specify-base"><title>Specifying the Base DN and Scope</title>
<indexterm>
<primary>base DN</primary>
<secondary>explained</secondary>
</indexterm><indexterm>
<primary>scope</primary>
<secondary>explained</secondary>
</indexterm>
<para>When sending a search request, you need to specify the base DN and scope
of the search to identify the entries that you want searched.</para>
<para>The base DN is the DN of the entry that serves as the starting point
of the search.</para>
<itemizedlist>
<para>To specify the scope of the search, you pass one of the following values
as the scope parameter:</para>
<listitem><para><constant>LDAPv3.SCOPE_SUB</constant> &mdash; Search the base
entry and all entries at all levels under the base entry.</para>
<mediaobject>
<imageobject><imagedata entityref="hiersrch"></imageobject>
<textobject><simpara>Subtree scope applies to everything below the base DN.</simpara>
</textobject>
</mediaobject>
</listitem>
<listitem><para><constant>LDAPv3.SCOPE_ONE</constant> &mdash; Search all entries
at one level under the base entry.</para>
<mediaobject>
<imageobject><imagedata entityref="hier1lvl"></imageobject>
<textobject><simpara>One level scope applies to all entries just below the
base DN.</simpara></textobject>
</mediaobject>
<para>The base entry is not included in the search. Use this setting if you
just want a list of the entries under a given entry.</para></listitem>
<listitem><para><constant>LDAPv3.SCOPE_BASE</constant> &mdash; Search only
the base entry.</para>
<mediaobject>
<imageobject><imagedata entityref="hierbase"></imageobject>
<textobject><simpara>Base scope applies only to the base DN entry.</simpara>
</textobject>
</mediaobject>
<para>Use this setting if you want to read the attributes of only the base
entry.</para></listitem>
</itemizedlist>
</sect2>
<sect2 id="searching-filter"><title>Specifying a Search Filter</title>
<indexterm>
<primary>filters</primary>
</indexterm><indexterm>
<primary>search filters</primary>
<secondary>specifying</secondary>
</indexterm>
<para>When you search the directory, you use a search filter to define the
search. Here is the basic syntax for a search filter:</para>
<programlisting>(<replaceable>attribute</replaceable> <replaceable>operator</replaceable> <replaceable>
value</replaceable>)</programlisting>
<para>Here is a simple example of a search filter:</para>
<programlisting>(cn=Barbara Jensen)</programlisting>
<para>In this example, <literal>cn</literal> is the attribute. <literal>=</literal> is
the operator. <literal>Barbara Jensen</literal> is the value. The filter finds
entries with the common name <literal>Barbara Jensen</literal>.</para>
<para>Valid attributes that you can use in your search filter are provided
in the documentation for the LDAP server.</para>
<para>Following are descriptions of valid operators for search filters, and
example filters that use the operators.</para>
<variablelist>
<varlistentry><term><literal>=</literal></term>
<listitem><para>Return entries whose attributes are equal to the value provided.</para>
<para>For example, the following filter matches Barbara Jensen's entry:</para>
<programlisting>(cn=Barbara Jensen)</programlisting>
</listitem>
</varlistentry>
<varlistentry><term><literal>>=</literal></term>
<listitem><para>Return entries whose attributes are greater than or equal
to the value provided.</para>
<para>For example, the following filter matches Barbara Jensen's entry and
entries for people with surnames following Jensen in alphabetic order, such
as entries with <literal>sn=Seuss</literal> and <literal>sn=Zhivago</literal>:</para>
<programlisting>(sn>=jensen)</programlisting>
</listitem>
</varlistentry>
<varlistentry><term><literal>&lt;=</literal></term>
<listitem><para>Return entries whose attributes are less than or equal to
the value provided.</para>
<para>For example, the following filter matches Barbara Jensen's entry and
entries for people with surnames that precede Jensen in alphabetic order,
such as entries with <literal>sn=Anderson</literal> and <literal>sn=Cubbins</literal>:
</para>
<programlisting>(sn&lt;=jensen)</programlisting>
</listitem>
</varlistentry>
<varlistentry><term><literal>=*</literal></term>
<listitem><para>Return entries that have a value set for the attribute (presence).
</para>
<para>For example, the following filter matches all entries that have a value
for the surname:</para>
<programlisting>(sn=*)</programlisting>
</listitem>
</varlistentry>
<varlistentry><term><literal>~=</literal></term>
<listitem><para>Return entries whose attribute value approximately matches
the specified value, such as the value sounds like the specified value.</para>
<para>For example, the following filter matches all entries with values for
surname that sound like Jensen, such as Barbara Jensen's entry, but also Emanuel
Johnson's entry:</para>
<programlisting>(sn~=jensen)</programlisting>
</listitem>
</varlistentry>
</variablelist>
<para>With Boolean operators and with parentheses, you can combine different
sets of conditions. Here is the syntax for combining search filters:</para>
<programlisting>(<replaceable>boolean</replaceable>(<replaceable>filter1</replaceable>)(<replaceable>
filter2</replaceable>)(&hellip;))</programlisting>
<para>Following are descriptions of the valid boolean operators.</para>
<variablelist>
<varlistentry><term><literal>&amp;</literal></term>
<listitem><para>Return entries that match all specified filters.</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>|</literal></term>
<listitem><para>Return entries that match one or more of the specified filters.</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>!</literal></term>
<listitem><para>Return entries that do not match the specified filter.</para>
<para>This operator is unary because you can apply the operator only to a
single set of results. In other words, to specify &ldquo;entries that match
neither <replaceable>filter1</replaceable> nor <replaceable>filter2</replaceable>,&rdquo;
use the syntax:</para>
<programlisting>(!(|(<replaceable>filter1</replaceable>)(<replaceable>filter2</replaceable>)))
</programlisting>
</listitem>
</varlistentry>
</variablelist>
<para>You can also include wildcard characters to search for entries that
start with, contain, or end with a given value. For example, you can use the
following filter to search for all entries with first names that begin with
the letter <literal>F</literal>:</para>
<programlisting>(givenName=F*)</programlisting>
</sect2>
<sect2 id="searching-specify-attrs"><title>Specifying the Attributes to Retrieve</title>
<indexterm>
<primary>attributes</primary>
<secondary>operational</secondary>
</indexterm><indexterm>
<primary>attributes</primary>
<secondary>retrieving in a search</secondary>
</indexterm><indexterm>
<primary>operational attributes</primary>
</indexterm>
<itemizedlist>
<para>With the <parameter>attrs</parameter> parameter, you can retrieve all
attributes in entries returned by the search. Alternatively, you can specify
the attributes that you want returned in the search results. For example,
you can specify to return the attributes in one of the following ways:</para>
<listitem><para>To return selected attributes, pass an array of the attribute
names as the <parameter>attrs</parameter> parameter. For example, to return
only email addresses and phone numbers, pass the array <literal>{"mail", "telephoneNumber"}
</literal> as the <parameter>attrs</parameter> parameter.</para></listitem>
<listitem><para>To return all attributes in an entry, pass <constant>null</constant> as
the <parameter>attrs</parameter> parameter.</para></listitem>
<listitem><para>To return no attributes from an entry, pass <constant>LDAPv3.NO_ATTRS
</constant> as the <parameter>attrs</parameter> parameter.</para></listitem>
</itemizedlist>
<para>You might plan to sort the results on your client as described in <olink
targetptr="searching-sorting">Sorting the Search Results With Directory SDK
for Java</olink>. Return the attributes that you plan to use for sorting.
For example, if you plan to sort by email address, make sure that the mail
attribute is returned in the search results.</para>
<para>Some attributes are used by servers for administering the directory.
For example, the <literal>creatorsName</literal> attribute specifies the DN
of the user who added the entry. These attributes are called <firstterm>operational
attributes</firstterm>.</para>
<para>Servers do not normally return operational attributes in search results
unless you specify the attributes by name. For example, if you pass <constant>null
</constant> as the <parameter>attrs</parameter> parameter to retrieve all
of the attributes in entries found by the search, the operational attribute <literal>
creatorsName</literal> is not returned to your client. You need to explicitly
specify the <literal>creatorsName</literal> attribute in the <parameter>attrs</parameter> parameter.
</para>
<para>To return all attributes in an entry with selected operational attributes,
pass a string array containing <constant>LDAPv3.ALL_USER_ATTRS</constant>,
and also the names of the operational attributes as the <parameter>attrs</parameter> parameter.
Following are a few operational attributes and a description of what each
attribute contains.</para>
<variablelist>
<varlistentry><term><literal>createTimestamp</literal></term>
<listitem><para>The time when the entry was added to the directory.</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>modifyTimestamp</literal></term>
<listitem><para>The time when the entry was last modified.</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>creatorsName</literal></term>
<listitem><para>Distinguished name (DN) of the user who added the entry to
the directory.</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>modifiersName</literal></term>
<listitem><para>DN of the user who last modified the entry.</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>subschemaSubentry</literal></term>
<listitem><para>DN of the subschema entry, that controls the schema for this
entry.</para>
</listitem>
</varlistentry>
</variablelist>
</sect2>
<sect2 id="searching-set-prefs"><title>Setting Search Preferences</title>
<para>For a given search, you can apply a set of preferences that determine
how the search is performed. For example, you can specify the maximum number
of results to be returned or the maximum amount of time to wait for a search.</para>
<para>The <classname>LDAPSearchConstraints</classname> class represents a
set of search constraints. The methods of this class allow you to get and
set the constraints.</para>
<sect3 id="searching-set-prefs-all"><title>Setting Preferences for All Searches</title>
<indexterm>
<primary>search results</primary>
<secondary>setting preferences</secondary>
</indexterm>
<para>The <classname>LDAPConnection</classname> object, which represents a
connection to the LDAP server, is associated with a default set of search
constraints. These constraints apply to all searches that you perform over
the connection.</para>
<itemizedlist>
<listitem><para>To get the default set of search constraints for the connection,
you can use the <literal>getSearchConstraints</literal> method.</para>
</listitem>
<listitem><para>To get or set any of the search constraints individually,
you can use the <literal>getOption</literal> method and the <literal>setOption</literal> method.
</para></listitem>
</itemizedlist>
<para>For example, if you want to specify the maximum number of results returned,
you can set this constraint for the connection:</para>
<programlisting>LDAPConnection ld = new LDAPConnection();
ld.connect("ldap.example.com", LDAPv3.DEFAULT_PORT);
ld.setOption(LDAPv3.SIZELIMIT, new Integer(100));</programlisting>
</sect3>
<sect3 id="searching-set-prefs-override"><title>Overriding Preferences for
Individual Searches</title>
<para>To override the default set of search constraints for a given search
request, construct your own <classname>LDAPSearchConstraints</classname> object.
Pass the object to the <literal>search</literal> method of the <classname>LDAPConnection
</classname> object.</para>
<para>You can also modify a copy of the existing search constraints. Pass
the modified set of constraints to the <literal>search</literal> method. Invoke
the <literal>getSearchConstraints</literal> method of the <classname>LDAPConnection
</classname> object to get the default set of constraints for that connection.
Then invoke the clone method of the <classname>LDAPSearchConstraints</classname> object
to make a copy of the set that you can then modify.</para></sect3>
<sect3 id="searching-set-prefs-wait"><title>Configuring the Search to Wait
for All Results</title>
<indexterm>
<primary>search results</primary>
<secondary>waiting for all</secondary>
</indexterm>
<para>By default, the <literal>search</literal> method of the <classname>LDAPConnection
</classname> object does not block until all results are received. Instead,
the <literal>search</literal> method returns as soon as one of the results
has been received.</para>
<itemizedlist>
<para>If you want the <literal>search</literal> method to block until all
results are received, you can do one of the following:</para>
<listitem><para>Use the <literal>setOption</literal> method of the <classname>LDAPConnection
</classname> object to set the <constant>LDAPv3.BATCHSIZE</constant> preference
to <literal>0</literal>.</para></listitem>
<listitem><para>Pass a <literal>0</literal> to the <literal>setBatchSize</literal> method
of the <classname>LDAPSearchConstraints</classname> object to change the behavior
for a particular set of search constraints.</para></listitem>
</itemizedlist>
<para>Whether waiting for one or all results of the <literal>search</literal> method,
you still need to invoke the <literal>next</literal> method of the returned <classname>
LDAPSearchResults</classname> object to retrieve each individual result.</para>
</sect3>
<sect3 id="searching-set-prefs-size"><title>Setting Size and Time Limits</title>
<indexterm>
<primary>search results</primary>
<secondary>setting size limits</secondary>
</indexterm><indexterm>
<primary>search results</primary>
<secondary>setting time limits</secondary>
</indexterm>
<para>By default, when you search the directory from a client that you built
with &DirectorySDKForJava;, the maximum number of entries to return is
set to <literal>1000</literal>. No maximum time limit is set for waiting on
an operation to complete.</para>
<itemizedlist>
<para>To change these default values, you can do one of the following:</para>
<listitem><para>Use the <literal>setOption</literal> method of the <classname>LDAPConnection
</classname> object to set the <constant>LDAPv3.SIZELIMIT</constant> and <constant>
LDAPv3.TIMELIMIT</constant> preferences.</para></listitem>
<listitem><para>Use the <literal>setMaxResults</literal> method and the <literal>
setTimeLimit</literal> method of the <classname>LDAPSearchConstraints</classname> object
to change the behavior for a particular set of search constraints.</para>
</listitem>
</itemizedlist>
<itemizedlist>
<para>When you set the size limit or time limit, you might cause an <classname>LDAPException
</classname> to be returned. The exception is returned when the limit is exceeded.
</para>
<listitem><para>If the size limit is exceeded, the server returns an <constant>LDAPException.SIZE_LIMIT_EXCEEDED
</constant> result code.</para></listitem>
<listitem><para>If the time limit is exceeded, the server returns an <constant>LDAPException.TIME_LIMIT_EXCEEDED
</constant> result code.</para></listitem>
</itemizedlist>
</sect3>
</sect2>
<sect2 id="searching-example-request"><title>Search Request Example</title>
<para>The following section of code searches for all entries with surname <literal>
Jensen</literal>. The search retrieves the names and values of the <literal>cn</literal>, <literal>
mail</literal>, and <literal>telephoneNumber</literal> attributes.</para>
<programlisting>LDAPConnection ld = null;
try {
/* Create a new LDAPConnection object. */
ld = new LDAPConnection();
/* Connect and bind to the server. */
String HOSTNAME = "localhost";
ld.connect(HOSTNAME, LDAPv3.DEFAULT_PORT, null, null);
/* Specify the search criteria. */
String baseDN = "dc=example,dc=com";
int searchScope = LDAPv3.SCOPE_SUB;
String searchFilter = "(sn=Jensen)";
String getAttrs[] = {"cn", "mail", "telephoneNumber"};
/* Send the search request. */
LDAPSearchResults res = ld.search(baseDN, searchScope,
searchFilter, getAttrs, false);
} catch(LDAPException e) {
System.out.println("Error: " + e.toString);
}</programlisting>
</sect2>
</sect1>
<sect1 id="searching-results"><title>Getting the Search Results With &DirectorySDKForJava;</title>
<indexterm>
<primary>search results</primary>
<secondary>getting</secondary>
</indexterm>
<para>When you invoke the <literal>search</literal> method of an <classname>LDAPConnection
</classname> object to search the directory, the method returns the search
results in the form of an <classname>LDAPSearchResults</classname> object.</para>
<para>The search results consist of an enumeration of entries, which are represented
by <classname>LDAPEntry</classname> objects. The search results can also include
smart referrals, also known as <firstterm>search references</firstterm>, and
exceptions.</para>
<para>Each entry contains a set of attributes, which are represented by <classname>
LDAPAttributeSet</classname> objects. Individual attributes are represented
by <classname>LDAPAttribute</classname> objects. Each attribute has a set
of values that you can get.</para>
<para>The following figure illustrates the relationship between entries, attributes,
values, and search results.</para>
<figure id="searching-result-set"><title>Entries, Attributes, and Values in
Search Results</title>
<mediaobject>
<imageobject><imagedata entityref="entries"></imageobject>
<textobject><simpara>Relationship between entries, attributes, values, and
search results</simpara></textobject>
</mediaobject>
</figure>
<sect2 id="searching-results-entries"><title>Getting Entries</title>
<indexterm>
<primary>entries</primary>
<secondary>getting from search results</secondary>
</indexterm><indexterm>
<primary>search results</primary>
<secondary>getting entries</secondary>
</indexterm>
<para>The <classname>LDAPSearchResults</classname> object represents the results
of the search. These results can include entries found by the search, search
references, and result codes. Your LDAP client can receive an <returnvalue>ADMIN_LIMIT_EXCEEDED
</returnvalue>, <returnvalue>TIME_LIMIT_EXCEEDED</returnvalue>, or <returnvalue>SIZE_LIMIT_EXCEEDED
</returnvalue> result code from the server. When the result code is received, &DirectorySDKForJava; adds
an exception for this result code to the search results.</para>
<para>To get entries from the <classname>LDAPSearchResults</classname> object,
you can either invoke the <literal>next</literal> method or the <literal>nextElement
</literal> method.</para>
<itemizedlist>
<listitem><para>When you invoke the <literal>next</literal> method, if the
next item in the search results is an entry, the method returns an <classname>LDAPEntry
</classname> object.</para>
<itemizedlist>
<para><indexterm>
<primary>referrals</primary>
<secondary><classname>LDAPReferralException</classname> and</secondary>
</indexterm><indexterm>
<primary>referrals</primary>
<secondary>getting from search results</secondary>
</indexterm>If the next item is a search reference, one of the following can
occur:</para>
<listitem><para>If referrals are not followed automatically, an <classname>LDAPReferralException
</classname> is returned. The exception is also returned if the referral hop
limit is exceeded.</para></listitem>
<listitem><para>The LDAP Java classes follow the referral when two conditions
are fulfilled. Referrals must be followed automatically, the referral hop
limit must not be exceeded. </para></listitem>
</itemizedlist>
<para>The classes also retrieve the entry for you. The method creates a new
connection to the server that is specified in the referral and attempts to
retrieve the entry from that server.</para><para>See <olink
targetptr="handling-referrals">Handling Referrals With Directory SDK for Java</olink> for
more information about referrals and search references.</para><para>If the
next item is an LDAP result code such as <returnvalue>ADMIN_LIMIT_EXCEEDED</returnvalue>, <returnvalue>
TIME_LIMIT_EXCEEDED</returnvalue>, or <returnvalue>SIZE_LIMIT_EXCEEDED</returnvalue>,
the LDAP Java classes return an <classname>LDAPException</classname>.</para>
</listitem>
<listitem><para>When you invoke the <literal>nextElement</literal> method,
the method returns an object that you must cast. The object is an <classname>LDAPEntry
</classname> object, an <classname>LDAPReferralException</classname>, or an <classname>
LDAPException</classname>.</para></listitem>
</itemizedlist>
<para>As you iterate through the search results, you can invoke the <literal>hasMoreElements
</literal> method to determine if you have reached the end of the search results.
</para>
<programlisting>LDAPConnection ld = null;
try {
/* Create a new LDAPConnection object. */
ld = new LDAPConnection();
/* Set up parameters for the search request... */
/* Send the search request. */
LDAPSearchResults res = ld.search(baseDN, searchScope,
searchFilter, getAttrs, false);
/* Iterate through the results until finished. */
while (res.hasMoreElements()) {
/* Get the next entry in the results. */
LDAPEntry findEntry = null;
try {
findEntry = res.next();
/* If it is a referral, print the LDAP URLs. */
} catch (LDAPReferralException e) {
System.out.println("Search references: ");
LDAPUrl refUrls[] = e.getURLs();
for (int i=0; i &lt; refUrls.length; i++) {
System.out.println("\t" + refUrls[i].getUrl());
}
continue;
} catch (LDAPException e) {
System.out.println("Error: " + e.toString());
continue;
}
/* Do something with the entry... */
}
} catch (LDAPException e) {
/* Handle exceptions arising outside the search... */
}</programlisting>
</sect2>
<sect2 id="searching-results-dns"><title>Getting Distinguished Names</title>
<indexterm>
<primary>distinguished names</primary>
<secondary>getting from search results</secondary>
</indexterm><indexterm>
<primary>search results</primary>
<secondary>getting distinguished names</secondary>
</indexterm>
<para>To get the distinguished name of an <classname>LDAPEntry</classname> object,
invoke the <literal>getDN</literal> method. This method returns a <classname>String
</classname>.</para>
<programlisting>LDAPEntry nextEntry = res.next();
String nextDN = nextEntry.getDN();</programlisting>
<para>Although the <literal>netscape.ldap</literal> package includes an <classname>
LDAPDN</classname> class, you typically do not construct objects of this class
to represent DNs. The <classname>LDAPDN</classname> class is mainly a utility
class that provides methods for manipulating string DNs.</para></sect2>
<sect2 id="searching-results-attrs"><title>Getting Attributes</title>
<indexterm>
<primary>attributes</primary>
<secondary>getting from search results</secondary>
</indexterm><indexterm>
<primary>search results</primary>
<secondary>getting attributes</secondary>
</indexterm>
<para>To get the set of attributes in an <classname>LDAPEntry</classname> object,
invoke the <literal>getAttributeSet</literal> method. This method returns
an <classname>LDAPAttributeSet</classname> object.</para>
<programlisting>LDAPEntry nextEntry = res.next();
LDAPAttributeSet entryAttrs = nextEntry.getAttributeSet();</programlisting>
<para>To get individual attributes from an <classname>LDAPAttributeSet</classname> object,
invoke the <literal>getAttributes</literal> method. This method returns an
enumeration of attributes. You can then iterate through the elements in this
enumeration to retrieve individual <classname>LDAPAttribute</classname> objects.</para>
<programlisting>/* Get the set of attributes for an entry. */
LDAPAttributeSet entryAttrs = nextEntry.getAttributeSet();
/* Get an enumeration of those attribute. */
Enumeration enumAttrs = entryAttrs.getAttributes();
/* Loop through the enumeration to get each attribute. */
while (enumAttrs.hasMoreElements()) {
LDAPAttribute attr = (LDAPAttribute)enumAttrs.nextElement();
System.out.println("Attribute type: " + attr.getName());
}</programlisting>
<para>To determine the number of attributes in the <classname>LDAPAttributeSet</classname> object,
invoke the <literal>size</literal> method.</para>
<itemizedlist>
<para>You can also retrieve a specific attribute from the entry or from the
attribute set.</para>
<listitem><para>To get a specific attribute from an <classname>LDAPEntry</classname> object,
invoke the <literal>getAttribute</literal> method.</para></listitem>
<listitem><para>To get a specific attribute from an <classname>LDAPAttributeSet</classname> object,
invoke the <literal>getAttribute</literal> method.</para></listitem>
</itemizedlist>
<para>Both methods return an <classname>LDAPAttribute</classname> object.</para>
<programlisting>LDAPEntry nextEntry = res.next();
LDAPAttribute anAttr = nextEntry.getAttribute("cn");</programlisting>
</sect2>
<sect2 id="searching-results-attr-types-values"><title>Getting Attribute Types
and Values</title>
<indexterm>
<primary>attributes</primary>
<secondary>getting from search results</secondary>
</indexterm><indexterm>
<primary>search results</primary>
<secondary>getting attribute types</secondary>
</indexterm><indexterm>
<primary>search results</primary>
<secondary>getting attribute values</secondary>
</indexterm>
<para>To get the name of an <classname>LDAPAttribute</classname> object, invoke
the <literal>getName</literal> method.</para>
<programlisting>LDAPAttribute nextAttr = (LDAPAttribute)enumAttrs.nextElement();
String attrName = nextAttr.getName();</programlisting>
<itemizedlist>
<para>To get the values in an <classname>LDAPAttribute</classname> object,
you can use the following methods:</para>
<listitem><para>To get the <classname>String</classname> values, invoke the <literal>
getStringValues</literal> method.</para></listitem>
<listitem><para>To get the binary values as byte arrays, invoke the <literal>getByteValues
</literal> method.</para></listitem>
</itemizedlist>
<para>Both methods return an enumeration that you can iterate through to retrieve
individual results. For example, if an error occurs when you invoke <literal>getStringValues
</literal>, although the values are binary data, the methods return <constant>null
</constant>.</para>
<para>You can also count the number of values in an attribute by invoking
the <literal>size</literal> method of the <classname>LDAPAttribute</classname> object.
</para>
<programlisting>LDAPAttribute nextAttr = (LDAPAttribute)enumAttrs.nextElement();
/* Get and print the attribute name. */
String attrName = nextAttr.getName();
System.out.println("\t" + attrName + ":");
/* Iterate through the attribute's values. */
Enumeration enumVals = nextAttr.getStringValues();
if (enumVals != null) {
while (enumVals.hasMoreElements()) {
String nextValue = (String)enumVals.nextElement();
System.out.println("\t\t" + nextValue);
}
}</programlisting>
</sect2>
</sect1>
<sect1 id="searching-sorting"><title>Sorting the Search Results With &DirectorySDKForJava;</title>
<indexterm>
<primary>search results</primary>
<secondary>sorting</secondary>
</indexterm><indexterm>
<primary>sorting search results</primary>
</indexterm>
<itemizedlist>
<para>With &DirectorySDKForJava;, you can sort the search results in two
ways.</para>
<listitem><para>You can specify that the LDAP server should sort the results
before returning the results to your client.</para><para>Send a server-side
sort control to the server as described in <olink targetptr="controls">Chapter&nbsp;10,
LDAP Controls With Directory SDK for Java</olink>. Server-side sorting might
work best if you specify a filter that uses an indexed attribute.</para>
</listitem>
<listitem><para>After you receive the results from the server, you can sort
the results on your client.</para><para>Specify the names of the attributes
that you want to use for sorting. You also need to specify whether or not
the sorting is done in ascending or descending order.</para></listitem>
</itemizedlist>
<para>You can sort the results on the client by invoking the sort method of
the <classname>LDAPSearchResults</classname> object.</para>
<para><indexterm>
<primary><classname>LDAPEntryComparator</classname> interface</primary>
<secondary>example of</secondary>
</indexterm><indexterm>
<primary><classname>LDAPEntryCompareAttrNames</classname> class</primary>
<secondary>example of</secondary>
</indexterm>When invoking this method, you need to pass a comparator object,
which is an object of a class that implements the <classname>LDAPEntryComparator</classname> interface. &DirectorySDKForJava; includes
an <classname>LDAPCompareAttrNames</classname> class that implements this
interface. This class specifies how entries are compared with each other and
sorted.</para>
<para>To construct an <classname>LDAPCompareAttrNames</classname> object,
you need to specify the attributes that you want to use for sorting and, optionally,
the sort order. When sorting on the client side, the attributes used for sorting
must be returned in the search results. If you are returning only a subset
of attributes in the search results, include the attributes that you specify
in the <classname>LDAPCompareAttrNames</classname> constructor. For example,
the following section of code sorts first by surname, <literal>sn</literal>,
and then by common name, <literal>cn</literal>, in ascending order:</para>
<programlisting>LDAPConnection ld = new LDAPConnection();
ld.connect("localhost", LDAPv3.DEFAULT_PORT);
LDAPSearchResults res = ld.search("dc=example,dc=com", LDAPv3.SCOPE_SUB,
"(objectclass=inetOrgPerson)", null, false);
String[] sortAttrs = {"sn", "cn"};
boolean[] ascending = {true, true};
res.sort(new LDAPCompareAttrNames(sortAttrs, ascending));</programlisting>
<para>If all search results have not yet been returned, the <literal>sort</literal> method
blocks until all results have been received.</para></sect1>
<sect1 id="searching-abandoning"><title>Abandoning a Search With &DirectorySDKForJava;</title>
<indexterm>
<primary>abandoning a search</primary>
</indexterm><indexterm>
<primary>searching the directory</primary>
<secondary>abandoning a search</secondary>
</indexterm>
<para>At any point during a search operation, you can send a request to the
server to abandon (cancel) the search. To abandon the search, use the <literal>abandon
</literal> method of the <classname>LDAPConnection</classname> object. Pass
in the <classname>LDAPSearchResults</classname> object that was returned to
you when you first invoked the <literal>search</literal> method.</para></sect1>
<sect1 id="searching-example"><title>Searching the Directory With &DirectorySDKForJava;</title>
<indexterm>
<primary>searching the directory</primary>
<secondary>example of</secondary>
</indexterm>
<para>The following example prints the values of all attributes in the entries
returned by a search.</para>
<example id="searching-example-code"><title>Searching for a Specific Entry</title>
<programlisting>import netscape.ldap.*;
import java.util.*;
public class Search {
public static void main(String[] args) {
try {
UserArgs userArgs = new UserArgs("Search", args, false);
LDAPConnection ld = new LDAPConnection();
ld.connect(userArgs.getHost(), userArgs.getPort());
/* search for all entries with surname of Jensen */
String MY_FILTER = "sn=Jensen";
String MY_SEARCHBASE = "dc=example,dc=com";
LDAPSearchConstraints cons = ld.getSearchConstraints();
/* Setting the batchSize to one will cause the result
enumeration below to block on one result at a time,
enabling an update of a list or other things as
results come in. */
/* This could be set to 0 in order to get all
results and to block until then. */
cons.setBatchSize(1);
LDAPSearchResults res = ld.search(MY_SEARCHBASE,
LDAPConnection.SCOPE_SUB, MY_FILTER, null, false, cons);
/* Loop on results until finished */
while (res.hasMoreElements()) {
LDAPEntry findEntry = null;
try {
findEntry = res.next();
} catch (LDAPReferralException e) {
System.out.println("Search reference: ");
LDAPUrl refUrls[] = e.getURLs();
for (int i=0; i&lt;refUrls.length; i++) {
System.out.println("\t" + refUrls[i].getUrl());
}
continue;
} catch (LDAPException e) {
System.out.println("Error: " + e.toString());
continue;
}
System.out.println(findEntry.getDN());
/* Get the attributes of the entry */
LDAPAttributeSet findAttrs = findEntry.getAttributeSet();
Enumeration enumAttrs = findAttrs.getAttributes();
System.out.println("\tAttributes: ");
/* Loop on attributes */
while (enumAttrs.hasMoreElements()) {
LDAPAttribute anAttr =
(LDAPAttribute)enumAttrs.nextElement();
String attrName = anAttr.getName();
System.out.println("\t\t" + attrName);
/* Loop on values for this attribute */
Enumeration enumVals = anAttr.getStringValues();
if (enumVals != null) {
while (enumVals.hasMoreElements()) {
String aVal = (String)enumVals.nextElement();
System.out.println("\t\t\t" + aVal);
}
}
}
}
ld.disconnect();
} catch(LDAPException e) {
System.out.println("Error: " + e.toString());
}
}
}</programlisting>
</example>
</sect1>
<sect1 id="searching-read"><title>Reading an Entry With &DirectorySDKForJava;</title>
<indexterm>
<primary>entries</primary>
<secondary>reading from directory</secondary>
</indexterm><indexterm>
<primary>reading an entry from the directory</primary>
</indexterm>
<para>To get a single entry from the directory, use the <literal>read</literal> method
of the <classname>LDAPConnection</classname> object. You can specify the DN
of the entry with the attributes that you want to retrieve, instead of retrieving
all attributes of the entry. You can also specify an LDAP URL that identifies
the entry that you want to retrieve.</para>
<para>To retrieve data from the entry, you can use the same classes with their
methods, as described in <olink targetptr="searching-results-attrs">Getting
Attributes</olink> and in <olink targetptr="searching-results-attr-types-values">
Getting Attribute Types and Values</olink>.</para>
<para>The following example retrieves an entry and prints the values of its
attributes.</para>
<example id="searching-example-code-read"><title>Retrieving a Specific Entry</title>
<programlisting>import netscape.ldap.*;
import java.util.*;
public class RdEntry {
public static void main(String[] args) {
try {
UserArgs userArgs = new UserArgs("PasswordPolicy", args, false);
LDAPConnection ld = new LDAPConnection();
ld.connect(userArgs.getHost(), userArgs.getPort());
String ENTRYDN = "uid=bjensen, ou=People, dc=example,dc=com";
/* Read all attributes */
LDAPEntry findEntry = ld.read(ENTRYDN);
System.out.println(findEntry.getDN());
/* Get the attributes of the entry */
LDAPAttributeSet findAttrs = findEntry.getAttributeSet();
Enumeration enumAttrs = findAttrs.getAttributes();
System.out.println("\tAttributes: ");
/* Loop on attributes */
while (enumAttrs.hasMoreElements()) {
LDAPAttribute anAttr =
(LDAPAttribute)enumAttrs.nextElement();
String attrName = anAttr.getName();
System.out.println("\t\t" + attrName);
/* Loop on values for this attribute */
Enumeration enumVals = anAttr.getStringValues();
if (enumVals != null) {
while (enumVals.hasMoreElements()) {
String aVal = (String)enumVals.nextElement();
System.out.println("\t\t\t" + aVal);
}
}
}
ld.disconnect();
} catch(LDAPException e) {
System.out.println("Error: " + e.toString());
}
}
}</programlisting>
</example>
</sect1>
<sect1 id="searching-child-entries"><title>Listing Child Entries With &DirectorySDKForJava;</title>
<indexterm>
<primary>entries</primary>
<secondary>retrieving child entries of</secondary>
</indexterm>
<para>To retrieve the entries directly beneath a particular entry, set the
starting point of the search to the entry. Also, set the scope of the search
to <constant>LDAPv3.SCOPE_ONE</constant>.</para>
<figure id="EWAUN"><title>Using Scope of One to Retrieve Child Entries</title>
<mediaobject>
<imageobject><imagedata entityref="hier1lvl" width="100"></imageobject>
<textobject><simpara>Search for child entries</simpara></textobject>
</mediaobject>
</figure>
<para>The following code performs a one-level search:</para>
<programlisting>LDAPConnection ld = null;
try {
ld = new LDAPConnection();
ld.connect("localhost", LDAPv3.DEFAULT_PORT);
LDAPSearchResults res = ld.search("dc=example,dc=com", LDAPv3.SCOPE_ONE,
"(objectclass=*)", null, false );
/* Loop on results until finished */
while (res.hasMoreElements()) {
LDAPEntry findEntry = null;
try {
findEntry = res.next();
/* If the next result is a referral, print the LDAP URLs. */
} catch (LDAPReferralException e) {
System.out.println("Search references: ");
LDAPUrl refUrls[] = e.getURLs();
for (int i=0; i &lt; refUrls.length; i++) {
System.out.println("\t" + refUrls[i].getUrl());
}
continue;
} catch ( LDAPException e ) {
System.out.println("Error: " + e.toString());
continue;
}
/* Print the DN of the entry. */
System.out.println(findEntry.getDN());
/* Get the attributes of the entry */
LDAPAttributeSet findAttrs = findEntry.getAttributeSet();
Enumeration enumAttrs = findAttrs.getAttributes();
System.out.println("\tAttributes: ");
/* Loop on attributes */
while (enumAttrs.hasMoreElements()) {
LDAPAttribute anAttr = (LDAPAttribute)enumAttrs.nextElement();
String attrName = anAttr.getName();
System.out.println("\t\t" + attrName);
/* Loop on values for this attribute */
Enumeration enumVals = anAttr.getStringValues();
if (enumVals != null) {
while (enumVals.hasMoreElements()) {
String aVal = (String)enumVals.nextElement();
System.out.println("\t\t\t" + aVal);
}
}
}
}
} catch( LDAPException e ) {
System.out.println("Error: " + e.toString());
}
/* Done, so disconnect. */
if ((ld != null) &amp;&amp; ld.isConnected()) {
try {
ld.disconnect();
} catch (LDAPException e) {
System.out.println("Error: " + e.toString());
}</programlisting>
</sect1>
</chapter>

View File

@@ -0,0 +1,575 @@
<!--
Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
Portions copyright 1999 Netscape Communications Corporation. All
Rights Reserved.
The contents of this document are subject to the terms of the
Creative Commons Attribution-ShareAlike 2.5 license or any later
version (the "License"). You may not use this document except in
compliance with the License.
See the License for the specific language governing
permissions and limitations under the License. You can obtain
a copy of the License at
http://creativecommons.org/licenses/by-sa/2.5/legalcode.
-->
<chapter id="server-info"><title>Getting Server Information With &DirectorySDKForJava;
</title>
<highlights>
<para>This chapter explains how to access and modify information about your
LDAP server over the LDAP protocol.</para>
<itemizedlist>
<para>This chapter covers the following topics:</para>
<listitem><para><olink targetptr="server-info-dse-intro">About DSEs</olink></para>
</listitem>
<listitem><para><olink targetptr="server-info-dse-info">Getting the Root DSE
With Directory SDK for Java</olink></para></listitem>
<listitem><para><olink targetptr="server-info-ldapv3">Checking Support for
LDAP v3 With Directory SDK for Java</olink></para></listitem>
<listitem><para><olink targetptr="server-info-schema">Getting Schema Information
With Directory SDK for Java</olink></para></listitem>
</itemizedlist>
</highlights>
<sect1 id="server-info-dse-intro"><title>About DSEs</title>
<para>The acronym <acronym>DSE</acronym> refers to a <emphasis>DSA-specific
entry</emphasis> in the directory. A DSA is a <emphasis>directory system agent</emphasis>,
an X.500 term for a directory server. A DSE contains information specific
to the server.</para>
<para>LDAP v3 uses the concept of the <firstterm>root DSE</firstterm>. In
a directory tree, the root of the tree is the root DSE. The root DSE is not
part of any naming context. In other words, the entry is superior to <literal>dc=example,dc=com
</literal>, <literal>cn=config</literal>, and similar suffixes in the directory
tree. Servers that do not support LDAP v3 therefore do not necessarily have
a root DSE.</para>
<itemizedlist>
<para>The root DSE can contain the following information:</para>
<listitem><para>The naming contexts the server supports, such as <literal>dc=example,dc=com
</literal> or <literal>cn=config</literal></para></listitem>
<listitem><para>URLs to alternate servers that can be contacted if the server
is unavailable</para></listitem>
<listitem><para>The LDAP v3 extended operations the server supports</para>
</listitem>
<listitem><para>The LDAP v3 controls the server supports</para></listitem>
<listitem><para>The SASL mechanisms the server supports</para></listitem>
<listitem><para>The versions of LDAP the server supports</para></listitem>
<listitem><para>Additional, server-specific information</para></listitem>
</itemizedlist>
</sect1>
<sect1 id="server-info-dse-info"><title>Getting the Root DSE With &DirectorySDKForJava;
</title>
<indexterm>
<primary>DSE</primary>
<secondary>root</secondary>
</indexterm><indexterm>
<primary>root DSE</primary>
</indexterm>
<para>The root DSE for an LDAP server specifies information about the server.
The attributes of the root DSE and what the attributes provide are shown here.</para>
<variablelist>
<varlistentry><term><literal>altServer</literal></term>
<listitem><para>LDAP URLs that identify other servers to contact when the
server is not available.</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>namingContexts</literal></term>
<listitem><para>Naming contexts, such as <literal>dc=example,dc=com</literal>,
supported by the server.</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>supportedControl</literal></term>
<listitem><para><firstterm>Object identifiers</firstterm> (OIDs) of LDAP v3
controls supported by the server.</para>
<para>If this attribute is not present, the server does not support LDAP v3
controls.</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>supportedExtension</literal></term>
<listitem><para>Object identifiers (OIDs) of LDAP v3 extended operations supported
by the server.</para>
<para>If this attribute is not present, the server does not support LDAP v3
extended operations.</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>supportedLDAPVersion</literal></term>
<listitem><para>Versions of LDAP, <literal>2</literal> or <literal>3</literal>,
supported by the server.</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>supportedSASLMechanisms</literal></term>
<listitem><para>Names of SASL mechanisms supported by the server.</para>
<para>If this attribute is not present, the server does not support any SASL
mechanisms.</para>
</listitem>
</varlistentry>
</variablelist>
<orderedlist>
<para>To access the root DSE of an LDAP server, do the following:</para>
<listitem><para>Turn off automatic referral handling, and connect to the LDAP
server.</para><para>See <olink type="auto-generated" targetptr="prepare-client">Creating
a Connection and Setting Preferences With Directory SDK for Java</olink> and <olink type="auto-generated" targetptr="connect-client">Connecting to an LDAP Server
With Directory SDK for Java</olink>. See also <olink type="auto-generated" targetptr="handling-referrals">Handling Referrals With Directory SDK for Java</olink> for
instructions.</para></listitem>
<listitem>
<itemizedlist>
<para>Search the directory with the following criteria:</para>
<listitem><para>Set the search scope to a <literal>base</literal> search.</para>
</listitem>
<listitem><para>Specify an empty string for the base DN.</para></listitem>
<listitem><para>Use the search filter <literal>(objectclass=*)</literal>.</para>
</listitem>
</itemizedlist>
<para>Refer to <olink type="auto-generated" targetptr="searching">Chapter&nbsp;4, Searching the Directory With Directory SDK for Java</olink> for instructions.</para>
<para>If an <classname>LDAPException</classname> is returned with a result
code such as <returnvalue>OPERATION_ERROR</returnvalue>, <returnvalue>PROTOCOL_ERROR
</returnvalue>, <returnvalue>REFERRAL</returnvalue>, or <returnvalue>NO_SUCH_OBJECT
</returnvalue>, the LDAP server probably does not support LDAP v3.</para>
</listitem>
</orderedlist>
<para>The following code excerpt retrieves the root DSE, and then displays
the attributes.</para>
<programlisting>/* Create a new connection. */
LDAPConnection ld = new LDAPConnection();
String hostname = "localhost";
int portnumber = LDAPv3.DEFAULT_PORT;
try {
/* Connect to the LDAP server. */
ld.connect(3, hostname, portnumber);
int MY_SCOPE = LDAPv3.SCOPE_BASE;
String MY_FILTER = "(objectclass=*)";
String MY_SEARCHBASE = "";
LDAPSearchResults res = ld.search(MY_SEARCHBASE,
MY_SCOPE, MY_FILTER, null, false);
/* There should be only one result (the root DSE). */
while (res.hasMoreElements()) {
LDAPEntry findEntry = (LDAPEntry)res.nextElement();
/* Get the attributes of the root DSE. */
LDAPAttributeSet findAttrs = findEntry.getAttributeSet();
Enumeration enumAttrs = findAttrs.getAttributes();
/* Iterate through each attribute. */
while (enumAttrs.hasMoreElements()) {
LDAPAttribute anAttr = (LDAPAttribute)enumAttrs.nextElement();
/* Get and print the attribute name. */
String attrName = anAttr.getName();
System.out.println(attrName);
/* Get the values of the attribute. */
Enumeration enumVals = anAttr.getStringValues();
/* Get and print each value. */
if (enumVals == null) {
System.out.println("\tNo values found.");
continue;
}
while (enumVals.hasMoreElements()) {
String aVal = (String)enumVals.nextElement();
System.out.println("\t" + aVal);
}
}
}
} catch( LDAPException e ) {
System.out.println("Error: " + e.toString());
}</programlisting>
</sect1>
<sect1 id="server-info-ldapv3"><title>Checking Support for LDAP v3 With &DirectorySDKForJava;
</title>
<indexterm>
<primary>LDAP servers</primary>
<secondary>protocol version supported</secondary>
</indexterm>
<para>You can determine what version an LDAP server supports by getting the <literal>
supportedLDAPVersion</literal> attribute from the root DSE. This attribute
should contain the value <literal>3</literal>. The attribute can also contain
other values, such as <literal>2</literal>, so iterate through the values
of this attribute.</para>
<para>You are not required to authenticate or bind before performing a search.
Unlike LDAP v2, LDAP v3 states that clients do not need to bind to the server
before performing LDAP operations. The following section of code connects
to an LDAP server. The code then determines whether the server supports LDAP
v3.</para>
<programlisting>/* Create a new connection. */
LDAPConnection ld = new LDAPConnection();
String hostname = "localhost";
int portnumber = LDAPv3.DEFAULT_PORT;
boolean supportsV3 = false;
try {
/* Connect to the LDAP server. */
ld.connect( 3, hostname, portnumber );
int MY_SCOPE = LDAPv3.SCOPE_BASE;
String MY_FILTER = "(objectclass=*)";
String MY_SEARCHBASE = "";
LDAPSearchResults res = ld.search(MY_SEARCHBASE,
MY_SCOPE, MY_FILTER, null, false);
/* There should be only one result (the root DSE). */
while (res.hasMoreElements()) {
LDAPEntry findEntry = (LDAPEntry)res.nextElement();
/* Get the supportedLDAPVersion attribute values. */
LDAPAttribute versionAttr =
findEntry.getAttribute("supportedLDAPVersion");
/* Check for "3". */
Enumeration enumVals = versionAttr.getStringValues();
if (enumVals == null) {
System.out.println("\tNo values found.");
continue;
}
while (enumVals.hasMoreElements()) {
String aVal = (String)enumVals.nextElement();
if (aVal.equalsIgnoreCase("3")) {
supportsV3 = true;
break;
}
}
}
} catch( LDAPException e ) {
System.out.println("Error: " + e.toString());
}
if (supportsV3) {
System.out.println("This server supports LDAP v3.");
} else {
System.out.println("This server does not support LDAP v3.");
}</programlisting>
</sect1>
<sect1 id="server-info-schema"><title>Getting Schema Information With &DirectorySDKForJava;
</title>
<indexterm>
<primary>LDAP servers</primary>
<secondary>schema</secondary>
</indexterm><indexterm>
<primary>schema</primary>
</indexterm>
<para>In LDAP v3, you can get LDAP schema over LDAP. You can also modify schema
over LDAP. This section explains how to carry out such modifications.</para>
<sect2 id="server-info-schema-overview"><title>Understanding Schema Over LDAP</title>
<para>An entry can specify the schema that defines the object classes, attributes,
syntaxes, and matching rules used by the directory. This entry is called the <firstterm>
subschema entry</firstterm>.</para>
<para>To find the DN of the subschema entry, get the <literal>subschemaSubentry</literal> operational
attribute from the root DSE or from any entry. This code excerpt demonstrates
how to retrieve the subschema entry DN.</para>
<programlisting>LDAPConnection ld = null;
try {
ld = new LDAPConnection();
ld.connect("localhost", LDAPv3.DEFAULT_PORT);
String [] schemaAttr = {"subschemaSubentry"};
LDAPEntry rootDSE = ld.read("", schemaAttr);
LDAPAttribute resAttr = rootDSE.getAttribute(schemaAttr[0]);
Enumeration enumVals = resAttr.getStringValues();
if (enumVals != null) {
while (enumVals.hasMoreElements()) {
System.out.println(schemaAttr[0] + ": " +
(String)enumVals.nextElement());
}
}
ld.disconnect();
} catch(LDAPException e) {
System.out.println("Error: " + e.toString());
}</programlisting>
<para>The subschema entry can have the following attributes.</para>
<variablelist>
<varlistentry><term><literal>objectClasses</literal></term>
<listitem><para>Specifies the object class definitions in the schema.</para>
<para>Each value of this attribute is an object class that is known to the
server.</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>attributeTypes</literal></term>
<listitem><para>Specifies the attribute type definitions in the schema.</para>
<para>Each value of this attribute is an attribute type that is known to the
server.</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>matchingRules</literal></term>
<listitem><para>Specifies the matching rule definitions in the schema.</para>
<para>Each value of this attribute is a matching rule that is known to the
server.</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>matchingRuleUse</literal></term>
<listitem><para>Specifies the use of a matching rule in the schema.</para>
<para>Each value of this attribute is a matching rule use description. A matching
rule use description specifies the OIDs of the attributes that can be used
with this extensible matching rule.</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>syntaxes</literal></term>
<listitem><para>Specifies the syntax definitions in the schema.</para>
<para>Each value of this attribute is syntax that is known to the server.</para>
</listitem>
</varlistentry>
</variablelist>
<para>In &DirectorySDKForJava;, the schema and elements in the schema are
represented by classes in the <literal>netscape.ldap</literal> package. These
classes include the following.</para>
<variablelist>
<varlistentry><term><classname>LDAPSchema</classname></term>
<listitem><para>Schema used by an LDAP server</para>
</listitem>
</varlistentry>
<varlistentry><term><classname>LDAPSchemaElement</classname></term>
<listitem><para>Base class that represents a generic element in the schema</para>
</listitem>
</varlistentry>
<varlistentry><term><classname>LDAPObjectClassSchema</classname></term>
<listitem><para>Object class description in the schema</para>
</listitem>
</varlistentry>
<varlistentry><term><classname>LDAPAttributeSchema</classname></term>
<listitem><para>Attribute type description in the schema</para>
</listitem>
</varlistentry>
<varlistentry><term><classname>LDAPMatchingRuleSchema</classname></term>
<listitem><para>Matching rule description in the schema</para>
</listitem>
</varlistentry>
<varlistentry><term><classname>LDAPMatchingRuleUseSchema</classname></term>
<listitem><para>Use of a matching rule in the schema</para>
</listitem>
</varlistentry>
<varlistentry><term><classname>LDAPSyntaxSchema</classname></term>
<listitem><para>Syntax description in the schema</para>
</listitem>
</varlistentry>
</variablelist>
<para>These classes with their methods handle the subschema entry by using
standard LDAP operations, such as <literal>search</literal> and <literal>modify</literal>.
</para></sect2>
<sect2 id="server-info-schema-get"><title>Getting Information About LDAP Schema</title>
<para>To get the schema for an LDAP v3 server, construct a new <classname>LDAPSchema
</classname> object. Then, invoke the <literal>fetchSchema</literal> method,
passing in an <classname>LDAPConnection</classname> object.</para>
<programlisting>LDAPConnection ld = new LDAPConnection();
/* Construct an LDAPSchema object to hold the schema to retrieve. */
LDAPSchema dirSchema = new LDAPSchema();
try {
ld.connect(hostname, portnumber, bindDN, bindPW);
/* Get the schema. Anonymous access is OK. */
dirSchema.fetchSchema(ld);
/* Use the schema. */
} catch (Exception e) {
System.err.println(e.toString());
}</programlisting>
</sect2>
<sect2 id="server-info-schema-objectclasses"><title>Working With Object Class
Descriptions</title>
<para>In the LDAP Java classes, the object class descriptions in a schema
are represented by objects of the <classname>LDAPObjectClassSchema</classname> class.
</para>
<itemizedlist>
<para>To get the object class descriptions from the schema, invoke one of
the following methods:</para>
<listitem><para>To get an enumeration of <classname>LDAPObjectClassSchema</classname> objects
that represent the object classes in the schema, invoke the <literal>getObjectClasses
</literal> method.</para></listitem>
<listitem><para>To get a specific object class description, invoke the <literal>getObjectClass
</literal> method and pass in the name of the object class.</para></listitem>
<listitem><para>To get an enumeration of the names of object classes in the
schema, invoke the <literal>getObjectClassNames</literal> method.</para>
</listitem>
</itemizedlist>
<itemizedlist>
<para>An object class description consists of the following information, which
you can retrieve by invoking methods of the <classname>LDAPObjectClassSchema</classname> object:
</para>
<listitem><para>An OID that identifies the object class, retrieved by invoking
the <literal>getOID</literal> method</para></listitem>
<listitem><para>A name that identifies the object class, retrieved by invoking
the <literal>getName</literal> method</para></listitem>
<listitem><para>A description that identifies the object class, retrieved
by invoking the <literal>getDescription</literal> method</para></listitem>
<listitem><para>A name that identifies the parent object class, retrieved
by invoking the <literal>getSuperior</literal> method</para></listitem>
<listitem><para>The list of required attributes, retrieved by invoking the <literal>
getRequiredAttributes</literal> method</para></listitem>
<listitem><para>The list of optional attributes that are allowed, retrieved
by invoking the <literal>getOptionalAttributes</literal> method</para>
</listitem>
</itemizedlist>
<para>To add an object class description to the schema, construct a new <classname>
LDAPObjectClassSchema</classname> object. You can specify the pieces of information
in the object as individual arguments or in a description formatted according
to <ulink url="http://www.ietf.org/rfc/rfc4517.txt" type="text_url">RFC 4517</ulink>, <citetitle>
Lightweight Directory Access Protocol (LDAP): Syntaxes and Matching Rules</citetitle>.
</para>
<para>Then, you can either invoke the <literal>add</literal> method of this
object or the <literal>addObjectClass</literal> method of the <classname>LDAPSchema
</classname> object.</para>
<para>To remove an object class description, invoke the <literal>remove</literal> method
of this object.</para></sect2>
<sect2 id="server-info-schema-attributetypes"><title>Working With Attribute
Type Descriptions</title>
<para>In the LDAP Java classes, the attribute type descriptions in a schema
are represented by objects of the <classname>LDAPAttributeSchema</classname> class.
</para>
<itemizedlist>
<para>To get the attribute type descriptions from the schema, invoke one of
the following methods:</para>
<listitem><para>To get an enumeration of <classname>LDAPAttributeSchema</classname> objects
that represent the attribute types in the schema, invoke the <literal>getAttributes
</literal> method.</para></listitem>
<listitem><para>To get a specific attribute type description, invoke the <literal>
getAttribute</literal> method and pass in the name of the attribute type.</para>
</listitem>
<listitem><para>To get an enumeration of the names of attribute types in the
schema, invoke the <literal>getAttributeNames</literal> method.</para>
</listitem>
</itemizedlist>
<itemizedlist>
<para>An attribute type description consists of the following information,
which you can retrieve by invoking methods of the <classname>LDAPAttributeSchema</classname> object:
</para>
<listitem><para>An OID that identifies the attribute type, retrieved by invoking
the <literal>getOID</literal> method</para></listitem>
<listitem><para>A name that identifies the attribute type, retrieved by invoking
the <literal>getName</literal> method</para></listitem>
<listitem><para>A description that identifies the attribute type, retrieved
by invoking the <literal>getDescription</literal> method</para></listitem>
<listitem><para>The syntax used by the attribute type, retrieved by invoking
the <literal>getSyntax</literal> method</para></listitem>
<listitem><para>An indication whether the attribute type is single-valued
or multivalued, retrieved by invoking the <literal>isSingleValued</literal> method
</para></listitem>
</itemizedlist>
<para>To add an attribute type description to the schema, construct a new <classname>
LDAPAttributeSchema</classname> object. You can specify the pieces of information
in the object as individual arguments or in a description formatted according
to <ulink url="http://www.ietf.org/rfc/rfc4517.txt" type="text_url">RFC 4517</ulink>, <citetitle>
Lightweight Directory Access Protocol (LDAP): Syntaxes and Matching Rules</citetitle>.
</para>
<para>Then, you can either invoke the <literal>add</literal> method of this
object or the <literal>addAttributeType</literal> method of the <classname>LDAPSchema
</classname> object.</para>
<para>To remove an <literal>attributeType</literal> description, invoke the <literal>
remove</literal> method of this object.</para></sect2>
<sect2 id="server-info-schema-matchingrules"><title>Working With Matching
Rule Descriptions</title>
<para>In the LDAP Java classes, the matching rule and matching rule use descriptions
in a schema are represented by objects of the <classname>LDAPMatchingRuleSchema</classname> class.
</para>
<itemizedlist>
<para>To get the matching rule descriptions from the schema, invoke one of
the following methods:</para>
<listitem><para>To get an enumeration of <classname>LDAPMatchingRuleSchema</classname> objects
that represent the matching rules in the schema, invoke the <literal>getMatchingRules
</literal> method.</para></listitem>
<listitem><para>To get a specific matching rule description, invoke the <literal>
getMatchingRule</literal> method and pass in the name of the matching rule.</para>
</listitem>
<listitem><para>To get an enumeration of the names of matching rules in the
schema, invoke the <literal>getMatchingRuleNames</literal> method.</para>
</listitem>
</itemizedlist>
<itemizedlist>
<para>A matching rule description consists of the following information, which
you can retrieve by invoking methods of the <classname>LDAPMatchingRuleSchema</classname> object:
</para>
<listitem><para>An OID that identifies the matching rule, retrieved by invoking
the <literal>getOID</literal> method</para></listitem>
<listitem><para>A name that identifies the matching rule, retrieved by invoking
the <literal>getName</literal> method</para></listitem>
<listitem><para>A description that identifies the matching rule, retrieved
by invoking the <literal>getDescription</literal> method</para></listitem>
<listitem><para>The syntax of the matching rule, retrieved by invoking the <literal>
getSyntax</literal> method</para></listitem>
</itemizedlist>
<para>To add a matching rule description to the schema, construct a new <classname>
LDAPMatchingSchema</classname> object. You can specify the pieces of information
in the object as individual arguments or in a description formatted according
to <ulink url="http://www.ietf.org/rfc/rfc4517.txt" type="text_url">RFC 4517</ulink>, <citetitle>Lightweight Directory Access Protocol (LDAP):
Syntaxes and Matching Rules</citetitle>.</para>
<para>Then, you can either invoke the <literal>add</literal> method of this
object or the <literal>addMatchingRule</literal> method of the <classname>LDAPSchema
</classname> object.</para>
<para>To remove a matching rule description, invoke the <literal>remove</literal> method
of this object.</para></sect2>
<sect2 id="server-info-schema-example"><title>Example of Working With Schema</title>
<para>The following example illustrates how to get the schema and how to add
object classes and attribute types.</para>
<programlisting>import netscape.ldap.*;
import java.util.*;
public class GetSchema {
public static void main(String[] args) {
try {
UserArgs userArgs = new UserArgs("GetSchema", args, true);
LDAPConnection ld = new LDAPConnection();
ld.connect(userArgs.getHost(), userArgs.getPort());
ld.authenticate(userArgs.getBindDN(), userArgs.getPassword());
/* Get the schema. */
LDAPSchema dirSchema = new LDAPSchema();
dirSchema.fetchSchema(ld);
/* Get and print the inetOrgPerson object class. */
LDAPObjectClassSchema objClass =
dirSchema.getObjectClass("inetOrgPerson");
if (objClass != null)
System.out.println("inetOrgPerson := " +
objClass.toString());
/* Get and print the userPassword attribute. */
LDAPAttributeSchema attrType =
dirSchema.getAttribute("userpassword");
if (attrType != null)
System.out.println("userPassword := " +
attrType.toString());
/* Add a new object class. Requires write access. */
String[] requiredAttrs = {"cn", "mail"};
String[] optionalAttrs = {"sn", "telephoneNumber"};
LDAPObjectClassSchema newObjClass =
new LDAPObjectClassSchema("newInetOrgPerson",
"1.2.3.4.5.6.7", "top", "Experiment",
requiredAttrs, optionalAttrs);
/* Add the new object class to the schema. */
newObjClass.add(ld);
/* Create a new attribute type "hairColor". */
LDAPAttributeSchema newAttrType =
new LDAPAttributeSchema("hairColor",
"1.2.3.4.5.4.3.2.1", "Blonde, red, etc",
LDAPAttributeSchema.cis, false);
/* Add the new attribute type to the schema. */
newAttrType.add(ld);
/* Fetch schema again to verify changes */
dirSchema.fetchSchema(ld);
/* Get and print the new attribute type. */
newAttrType = dirSchema.getAttribute("hairColor");
if (newAttrType != null)
System.out.println("hairColor := " +
newAttrType.toString());
/* Get and print the new object class. */
newObjClass = dirSchema.getObjectClass("newInetOrgPerson");
if (newObjClass != null)
System.out.println("newInetOrgPerson := " +
newObjClass.toString());
ld.disconnect();
} catch ( Exception e ) {
System.err.println(e.toString());
System.exit(1);
}
}
}</programlisting>
</sect2>
</sect1>
</chapter>

View File

@@ -0,0 +1,209 @@
<!--
Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
Portions copyright 1999 Netscape Communications Corporation. All
Rights Reserved.
The contents of this document are subject to the terms of the
Creative Commons Attribution-ShareAlike 2.5 license or any later
version (the "License"). You may not use this document except in
compliance with the License.
See the License for the specific language governing
permissions and limitations under the License. You can obtain
a copy of the License at
http://creativecommons.org/licenses/by-sa/2.5/legalcode.
-->
<chapter id="ssl"><title>SSL Connections With &DirectorySDKForJava;</title>
<highlights>
<para>This chapter describes the process of enabling an LDAP client to connect
to an LDAP server over the Secure Sockets Layer (SSL) protocol. The chapter
explains how to connect to an LDAP server with SSL. It also covers SSL authentication.
</para>
<itemizedlist>
<para>This chapter covers the following topics:</para>
<listitem><para><olink targetptr="ssl-overview">How SSL Works With Directory
SDK for Java</olink></para></listitem>
<listitem><para><olink targetptr="ssl-prerequisites">Prerequisites for Connecting
Over SSL With Directory SDK for Java</olink></para></listitem>
<listitem><para><olink targetptr="ssl-connecting">Connecting to a Server Over
SSL With Directory SDK for Java</olink></para></listitem>
<listitem><para><olink targetptr="ssl-cert-based-auth">Using Certificate-Based
Client Authentication With Directory SDK for Java</olink></para></listitem>
</itemizedlist>
</highlights>
<sect1 id="ssl-overview"><title>How SSL Works With &DirectorySDKForJava;</title>
<para>&DirectorySDKForJava; includes classes and methods to enable your
application to connect to an LDAP server over a <firstterm>Secure Sockets
Layer</firstterm> (SSL).</para>
<sect2 id="ssl-overview-overview"><title>Understanding SSL</title>
<para>The primary goal of the SSL Protocol is to provide privacy and reliability
between two communicating applications. For more information about SSL and <firstterm>
Transport Layer Security</firstterm>, refer to <ulink
url="http://www.ietf.org/rfc/rfc2246.txt" type="text">RFC 2246</ulink>, <emphasis>
The TLS Protocol</emphasis>.</para>
<para>The &DirectorySDKForJava; supports SSL 3.0.</para></sect2>
<sect2 id="ssl-ldap"><title>SSL and LDAP</title>
<para>When an LDAP client connects to an LDAP server over SSL, the LDAP server
identifies itself by sending its <firstterm>certificate</firstterm> to the
LDAP client. The LDAP client needs to determine whether or not the <firstterm>certificate
authority</firstterm> (CA) who issued the certificate is trusted.</para>
<para>The LDAP server can also request that the client send a certificate
to authenticate. This process is called <firstterm>certificate-based client
authentication</firstterm>.</para>
<para>After receiving the client's certificate, the LDAP server determines
whether or not the CA who issued the certificate is trusted. If the CA is
trusted, the server uses the subject name in the certificate. With the subject
name, the server determines if the client has access rights to perform the
requested operation.</para>
<para>To use SSL, you need a <firstterm>certificate database</firstterm> to
hold the CA certificate. If certificate-based client authentication is used,
you need the client certificate.</para></sect2>
<sect2 id="ssl-interfaces-classes"><title>Interfaces and Classes for SSL</title>
<para>&DirectorySDKForJava; includes the <classname>LDAPSocketFactory</classname> interface.
This interface describes a single method, <literal>makeSocket</literal>, that
returns a socket to a given server specified by a host name and port number.
To establish an SSL connection, you need to create an object of a class that
implements this interface.</para>
<para>Classes that implement this interface rely on a separate class that
implements SSL sockets. In the constructors for objects that implement <classname>
LDAPSocketFactory</classname>, you typically need to specify the name of a
class that implements SSL sockets. The following classes implement this interface.
</para>
<variablelist>
<varlistentry><term><classname>LDAPSSLSocketFactory</classname></term>
<listitem><para>Use this class if you are using the <classname>netscape.net.SSLSocket
</classname> class to implement SSL sockets. You can also use this class if
the class that implements SSL sockets extends the <classname>Socket</classname> object.
</para>
</listitem>
</varlistentry>
<varlistentry><term><classname>LDAPSSLSocketWrapFactory</classname></term>
<listitem><para>Use this class if the class that implements SSL sockets does
not extend the <classname>Socket</classname> object. The <classname>LDAPSSLSocketWrapFactory
</classname> class wraps your SSL socket implementation class in a class that
does extend the <classname>Socket</classname> object.</para>
</listitem>
</varlistentry>
<varlistentry><term><classname>JSSESocketFactory</classname></term>
<listitem><para>Use this class to rely on the standard SSL socket factory
code.</para>
</listitem>
</varlistentry>
</variablelist>
<para>You can construct an object for one of these factory classes. You can
pass the factory object to the constructor for the <classname>LDAPConnection</classname> object,
to identify the socket factory that is used for the connection.</para></sect2>
</sect1>
<sect1 id="ssl-prerequisites"><title>Prerequisites for Connecting Over SSL
With &DirectorySDKForJava;</title>
<itemizedlist>
<para>The LDAP Java classes that enable you to connect over SSL assume the
following:</para>
<listitem><para>Your client has access to a Netscape Security Services (NSS)
certificate database.</para><para>If your client runs in a Netscape or Mozilla
browser, you can use the browser certificate database. With the browser certificate
database, you can determine if you trust the certificate that is sent from
the server.</para></listitem>
<listitem><para>The database used contains one of the following certificates:</para>
<itemizedlist>
<listitem><para>The certificate of the CA who issued the server certificate</para>
</listitem>
<listitem><para>If the CAs are organized hierarchically, the certificate of
any CA in the hierarchy</para></listitem>
<listitem><para>The certificate of the server</para></listitem>
</itemizedlist>
</listitem>
<listitem><para>The CA certificate is marked as <literal>trusted</literal> in
the database.</para></listitem>
<listitem><para>If you use certificate-based client authentication, you must
have the following data:</para>
<itemizedlist>
<listitem><para>A client certificate issued by a CA trusted by the LDAP server</para>
<para>This certificate must be in the client certificate database.</para>
</listitem>
<listitem><para>A public key, private key pair in an NSS key database on the
client side</para></listitem>
</itemizedlist>
</listitem>
</itemizedlist>
<para>When your client sends an initial request to the secure LDAP server,
the server sends its certificate back to your client. Your client determines
which CA issued the server's certificate. Your client then searches the certificate
database for the certificate of the issuing CA.</para>
<para>Your client might not find the CA certificate. Your client might also
find that the CA certificate is marked as <literal>not trusted</literal>.
If either condition occurs, your client refuses to connect to the server.</para>
<para>If you are using certificate-based client authentication, your client
retrieves its certificate from the certificate database. Your client sends
the certificate to the server for authentication. The server determines which
CA issued the client certificate. The server then searches its certificate
database for the certificate of the issuing CA.</para>
<para>The server might not find the CA certificate. The CA certificate might
be marked as <literal>not trusted</literal>. If either condition occurs, the
server refuses to authenticate your client.</para></sect1>
<sect1 id="ssl-connecting"><title>Connecting to a Server Over SSL With &DirectorySDKForJava;</title>
<orderedlist>
<para>To connect to an LDAP server with SSL, do the following:</para>
<listitem><para>Construct a new <classname>LDAPSSLSocketFactory</classname> object
or a new <classname>LDAPSSLSocketWrapFactory</classname> object.</para><para>This
object represents the SSL socket factory used to create the sockets for establishing
connections with the LDAP server.</para><para>The constructors for these classes
allow you to specify the name of the class used to create the actual sockets.</para>
<itemizedlist>
<listitem><para>For the <literal>LDAPSSLSocketFactory</literal> constructor,
you should specify a class that implements the <classname>javax.net.ssl.SSLSocket
</classname> interface. By default, if you do not specify a class, the <classname>
netscape.net.SSLSocket</classname> class is used.</para></listitem>
<listitem><para>If the SSL socket class does not extend the <classname>Socket</classname> class,
use the <classname>LDAPSSLSocketWrapFactory</classname> constructor.</para>
</listitem>
</itemizedlist>
</listitem>
<listitem><para>Pass the object that you constructed to the <literal>LDAPConnection
</literal> constructor.</para><para>When first you establish a connection
to the LDAP server, use the <literal>makeSocket</literal> method of the specified
object that you used to construct the socket.</para></listitem></orderedlist>
</sect1>
<sect1 id="ssl-cert-based-auth"><title>Using Certificate-Based Client Authentication
With &DirectorySDKForJava;</title>
<indexterm>
<primary>authentication</primary>
<secondary>certificate-based</secondary>
</indexterm><indexterm>
<primary>certificate-based client authentication</primary>
</indexterm>
<para>Some LDAP servers might be configured to use certificate-based client
authentication. A server might request that your client sends a certificate
to identify itself.</para>
<itemizedlist>
<para>With &DirectorySDKForJava;, you can set up your client to perform
certificate-based authentication in either of the following situations:</para>
<listitem><para>Your client runs as an applet in a Netscape or Mozilla browser</para>
</listitem>
<listitem><para>Your client uses a class implementing the <classname>LDAPSocketFactory
</classname> interface and supporting client-based authentication</para>
</listitem>
</itemizedlist>
<itemizedlist>
<para>When using certificate-based client authentication, consider the following:
</para>
<listitem><para>The <classname>LDAPSSLSocketWrapFactory</classname> class
does not support certificate-based client authentication.</para></listitem>
<listitem><para>The <classname>LDAPSSLSocketFactory</classname> class relies
on the browser to support certificate-based client authentication. The class
does not support the use of certificates for authentication outside the browser,
in stand-alone Java applications.</para></listitem>
</itemizedlist>
<orderedlist>
<para>To enable an applet to use certificate-based client authentication,
do the following:</para>
<listitem><para>Construct a new <classname>LDAPSSLSocketFactory</classname> object.
</para></listitem>
<listitem><para>Invoke the <literal>enableClientAuth</literal> method of the
object to enable certificate-based client authentication.</para></listitem>
<listitem><para>Pass the object that you constructed to the <literal>LDAPConnection
</literal> constructor.</para></listitem></orderedlist>
</sect1>
</chapter>

View File

@@ -0,0 +1,412 @@
<!--
Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
Portions copyright 1999 Netscape Communications Corporation. All
Rights Reserved.
The contents of this document are subject to the terms of the
Creative Commons Attribution-ShareAlike 2.5 license or any later
version (the "License"). You may not use this document except in
compliance with the License.
See the License for the specific language governing
permissions and limitations under the License. You can obtain
a copy of the License at
http://creativecommons.org/licenses/by-sa/2.5/legalcode.
-->
<chapter id="understanding-jdk"><title>Understanding the &DirectorySDKForJava;</title>
<highlights>
<para>This chapter describes the LDAP Java classes and the &DirectorySDKForJava;,
including the following sections:</para>
<itemizedlist>
<listitem><para><olink targetptr="understanding-java-classes">Understanding the LDAP
Java Classes</olink></para></listitem>
<listitem><para><olink targetptr="getting-started">About &DirectorySDKForJava;</olink></para>
</listitem>
</itemizedlist>
</highlights>
<sect1 id="understanding-java-classes"><title>Understanding the LDAP Java Classes
</title>
<indexterm>
<primary>packages</primary>
<secondary>summary of</secondary>
</indexterm><indexterm>
<primary>&DirectorySDKForJava;</primary>
<secondary>packages</secondary>
</indexterm>
<para>The &DirectorySDKForJava; includes the LDAP Java classes, which you use to
build LDAP clients. The LDAP Java classes allow you to write client applications that
connect to LDAP servers and perform standard LDAP operations. For example, you can
search for entries or add, update, or delete entries.</para>
<para>The classes are organized in the following packages:</para>
<variablelist>
<varlistentry><term><literal>com.netscape.sasl</literal></term>
<listitem><para>Contains the interfaces and classes that you can use to enable your
client to authenticate by using a SASL mechanism.</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>com.netscape.sasl.mechanisms</literal></term>
<listitem><para>Contains an implementation of the EXTERNAL SASL mechanism driver.
</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>netscape.ldap</literal></term>
<listitem><para>Contains the main LDAP Java classes, including classes that allow
you to connect to an LDAP server, manipulate entries and attributes, and retrieve
search results</para>
</listitem>
</varlistentry>
<!--<varlistentry><term><literal>netscape.ldap.beans</literal></term>
<listitem><para>Contains LDAP <trademark>JavaBeans
</trademark> technology. You can use LDAP JavaBeans
classes in a development environment such as Sun Java
Studio.</para>
</listitem>
</varlistentry>-->
<varlistentry><term><literal>netscape.ldap.ber.stream</literal></term>
<listitem><para>Contains the LDAP Java classes that implement the <firstterm>Basic
Encoding Rules</firstterm> (BER) for transfer syntax. For more information on BER,
see ISO/IEC 8825 at <ulink url="http://www.iso.ch/" type="url">http://www.iso.ch/
</ulink>.</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>netscape.ldap.controls</literal></term>
<listitem><para>Contains the LDAP Java classes that implement specific LDAP v3 controls.
These include controls to request server-side sorting and persistent searches.</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>netscape.ldap.factory</literal></term>
<listitem><para>Contains classes that allow you to create an SSL socket connection
to a server.</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>netscape.ldap.util</literal></term>
<listitem><para>Contains utility classes, such as classes to parse LDIF data and filters
that allow regular expression matching.</para>
</listitem>
</varlistentry>
</variablelist>
<para>Clients typically execute methods in the &DirectorySDKForJava; synchronously.
All LDAP operations block until they are completed, except for the <literal>search
</literal> method, which can return information before all the results have been received.
</para>
<para>An asynchronous interface is also provided for circumstances requiring low-level
interaction with an LDAP server. The asynchronous interface is discussed more fully
in <olink targetptr="asynchronous">Chapter&nbsp;33, Writing Asynchronous Clients With Directory SDK for Java</olink>.</para></sect1>
<sect1 id="getting-started"><title>About &DirectorySDKForJava;</title>
<para>This section covers the following topics:</para>
<itemizedlist>
<!--<listitem><para><olink targetptr="install-jdk">Getting
and Installing the Directory SDK for Java</olink></para>
</listitem>-->
<listitem><para><olink targetptr="explore-jdk">Exploring the Directory SDK for Java
</olink></para></listitem>
<listitem><para><olink targetptr="prepare-jdk">Preparing to Use Directory SDK for
Java</olink></para></listitem>
<!--<listitem><para><olink targetptr="applets-jdk"></olink></para>
</listitem><listitem><para><olink targetptr="version-jdk"></olink></para>
</listitem><listitem><para><olink targetptr="javabeans-jdk"></olink></para>
</listitem><listitem><para><olink targetptr="javascript-jdk"></olink></para>
</listitem>-->
</itemizedlist>
<!--<sect2 id="install-jdk"><title>Getting and Installing
the &DirectorySDKForJava;</title>
<indexterm>
<primary>&DirectorySDKForJava;</primary>
<secondary>installing</secondary>
</indexterm>
<para>TODO</para></sect2>-->
<sect2 id="explore-jdk"><title>Exploring the &DirectorySDKForJava;</title>
<indexterm>
<primary>&DirectorySDKForJava;</primary>
<secondary>contents</secondary>
</indexterm>
<para>TODO: verify this is all still true</para>
<para>The &DirectorySDKForJava; contains the following directories:</para>
<variablelist>
<!--<varlistentry><term><filename class="directory">beans
</filename></term>
<listitem><para>This directory contains the LDAP JavaBeans
class files from the <literal>netscape.ldap.beans
</literal> package.</para>
<para>If you are writing applications or applets that
use these classes, make sure to provide these classes
to your users.</para>
<para>This directory also contains a script to create
JAR files for the LDAP JavaBeans classes.</para>
</listitem>
</varlistentry><varlistentry><term><filename class="directory">
examples</filename></term>
<listitem><para>This directory contains sample source
code for LDAP Java applications. The examples are
organized in different subdirectories:</para>
<variablelist>
<varlistentry><term><filename class="directory">java
</filename></term>
<listitem><para>Contains examples of the standard
LDAP operations, such as adding an entry and searching
for entries. This directory also contains examples
using LDAP controls.</para>
</listitem>
</varlistentry>
<varlistentry><term><filename class="directory">java/beans
</filename></term>
<listitem><para>Contains examples uses of the LDAP
JavaBeans classes.</para>
</listitem>
</varlistentry>
<varlistentry><term><filename class="directory">java/ldapfilt
</filename></term>
<listitem><para>Contains an example uses of an LDAP
filter configuration file with the LDAP filter classes.
</para>
</listitem>
</varlistentry>
<varlistentry><term><filename class="directory">js
</filename></term>
<listitem><para>Contains an example of using LiveConnect
to create and manipulate LDAP Java objects from JavaScript.
LiveConnect enables communication in a single page
between a variety of elements such as JavaScript code,
HTML, browser plug-ins, and Java applets.</para>
</listitem>
</varlistentry>
</variablelist>
</listitem>
</varlistentry>-->
<varlistentry><term><filename class="directory">packages</filename></term>
<listitem><para>This directory contains the following JAR file<!--s-->:</para>
<variablelist>
<varlistentry><indexterm>
<primary>ldapjdk.jar</primary>
</indexterm><term><filename>ldapjdk.jar</filename></term>
<listitem><para>Contains classes for all packages listed in <olink targetptr="understanding-java-classes">
Understanding the LDAP Java Classes</olink><!--, but does not contain the filter classes-->
</para>
</listitem>
</varlistentry>
<!--<varlistentry><indexterm>
<primary>ldapfilt.jar</primary>
</indexterm><term><filename>ldapfilt.jar</filename></term>
<listitem><para>Contains the filter classes in the <literal>
netscape.ldap.util</literal> package, and the underlying
regular expression classes needed by the filter classes
</para>
</listitem>
</varlistentry>-->
</variablelist>
</listitem>
</varlistentry>
<varlistentry><term><filename class="directory">tools</filename></term>
<listitem><para>This directory contains Java classes for the <command>LDAPDelete</command>, <command>
LDAPModify</command>, and <command>LDAPSearch</command> commands.</para>
</listitem>
</varlistentry>
</variablelist>
</sect2>
<sect2 id="prepare-jdk"><title>Preparing to Use &DirectorySDKForJava;</title>
<indexterm>
<primary><envar>CLASSPATH</envar></primary>
<secondary>setting</secondary>
</indexterm>
<para>TODO: is this right?</para>
<para>Before compiling applications, add the following to your <envar>CLASSPATH</envar> environment
variable:</para>
<variablelist>
<!--<varlistentry><term><filename>beans/*.jar</filename></term>
<listitem><para>Containing the LDAP JavaBeans classes
</para>
</listitem>
</varlistentry>-->
<varlistentry><term><filename>packages/ldapjdk.jar</filename></term>
<listitem><para>Containing the main LDAP Java classes</para>
</listitem>
</varlistentry>
<!--<varlistentry><term><filename>packages/ldapfilt.jar
</filename></term>
<listitem><para>Containing the LDAP classes for handling
search filters</para>
</listitem>
</varlistentry>-->
</variablelist>
</sect2>
<!--<sect2 id="applets-jdk"><title>Writing Applets with
the &DirectorySDKForJava;</title>
<indexterm>
<primary>applets</primary>
<secondary>security framework and</secondary>
</indexterm><indexterm>
<primary>&DirectorySDKForJava;</primary>
<secondary>writing applets for</secondary>
</indexterm><indexterm>
<primary>LDAP clients</primary>
<secondary>writing applets</secondary>
</indexterm>
<para>TODO: Get this up to date. None of it seems
to work.</para>
<para>In <trademark>Netscape</trademark> Communicator,
an applet can connect to servers on hosts other than
the host that served the applet. This capability is
part of the new signed applet security framework.
To take advantage of this capability, your applet
class, the class making an LDAP connection, must be
signed. Your applet class needs to request certain
special rights before connecting to other servers.
</para>
<para>The steps to enable your applet to connect to
other LDAP servers are as follows:</para>
<orderedlist>
<listitem><para>Get a certificate from your organization's
certificate authority or from a third-party certificate
authority, such as RSA, Verisign, or ATT.</para><para>
Users should have the certificate from the certificate
authority in the Communicator certificate database.
</para></listitem>
<listitem><para>Create a JAR file with your classes
and have them signed.</para></listitem>
<listitem><para>Add the following line to your applet
code in the thread where you invoke <literal>LDAPConnection.connect
</literal>:</para>
<programlisting>PrivilegeManager.enablePrivilege("UniversalConnect");
</programlisting>
<para>At this point in the code, the user of your
applet will be prompted with a dialog box identifying
the author of the signed class and asking permission
to grant the right to access the LDAP server. The
user can either allow access for this time only or
forever.</para></listitem></orderedlist>
<para>TODO: fix this.</para>
<para>If you want to test the ability for your applet
to connect to hosts other than the originating one
without using object signing and certificates, in
case you want to test your applet while waiting for
your certificate to be issued for example, you can
configure Netscape Communicator to bypass this check.
</para>
<orderedlist>
<listitem><para>Exit Communicator or make sure that
it is not running.</para></listitem>
<listitem><para>Add the following line to the <filename>
prefs.js</filename> file: </para>
<programlisting>user_pref("signed.applets.codebase_principal_support", true);
</programlisting>
</listitem></orderedlist>
</sect2><sect2 id="version-jdk"><title>Checking the
Version of Classes from an Applet</title>
<indexterm>
<primary>applets</primary>
<secondary>checking version of LDAP classes</secondary>
</indexterm>
<para>To get the version number, invoke the <literal>
LDAPConnection.getProperty</literal> method and pass
in the constant <literal>LDAPConnection.LDAP_PROPERTY_SDK
</literal>. The version number is a <classname>Float
</classname> type. For example:</para>
<programlisting>Float sdkVersion = (Float)myConn.getProperty(myConn.LDAP_PROPERTY_SDK);
System.out.println("LDAP Java Classes version: " + sdkVersion);
</programlisting>
</sect2><sect2 id="javabeans-jdk"><title>Working with
LDAP JavaBeans Classes</title>
<indexterm>
<primary>JavaBeans classes</primary>
</indexterm><indexterm>
<primary>LDAP JavaBeans classes</primary>
</indexterm><indexterm>
<primary>&DirectorySDKForJava;</primary>
<secondary>LDAP JavaBeans classes</secondary>
</indexterm>
<para>The JavaBeans classes are part of the <literal>
netscape.ldap.beans</literal> package. Class files
are located in the <filename class="directory">beans
</filename> directory. The following JavaBeans classes
are included with the &DirectorySDKForJava;:</para>
<variablelist>
<varlistentry><term><classname>DisplayString</classname></term>
<listitem><para>Extends <classname>java.awt.TextArea
</classname> to help you display results from some
of the JavaBeans classes.</para>
</listitem>
</varlistentry>
<varlistentry><term><classname>LDAPBasePropertySupport
</classname></term>
<listitem><para>Exists as a base class specifying
accessor methods inherited by the other LDAP JavaBeans
classes.</para>
</listitem>
</varlistentry>
<varlistentry><term><classname>LDAPGetEntries</classname></term>
<listitem><para>Allows you to search the directory
and get an array of the DNs found by the search.</para>
<para>You can use the properties of this class to
specify the search criteria. The <literal>getEntries
</literal> method performs the search and sets the <property>
Result</property> property to the array of DNs found.
</para>
</listitem>
</varlistentry>
<varlistentry><term><classname>LDAPGetProperty</classname></term>
<listitem><para>Allows you to find an entry in the
directory and get the values of a specified attribute
in that entry.</para>
<para>You can use the properties of this class to
specify the search criteria. The <literal>getProperty
</literal> method performs the search and sets the <property>
Result</property> property to the array of the string
values of the specified attribute.</para>
</listitem>
</varlistentry>
<varlistentry><term><classname>LDAPIsMember</classname></term>
<listitem><para>Determines whether a user belongs
to a group.</para>
<para>Both the user and group can be specified as
properties of the class. The <literal>isMember</literal> method
sets the <property>Result</property> property to the
string <literal>Y</literal>or <literal>N</literal> to
indicate whether the user is a member.</para>
</listitem>
</varlistentry>
<varlistentry><term><classname>LDAPSimpleAuth</classname></term>
<listitem><para>Authenticates to an LDAP server.</para>
<para>After attempting to authenticate, the <literal>
authenticate</literal> method sets the <property>
Result</property> property to the string <literal>
Y</literal>or <literal>N</literal> to indicate whether
the authentication was successful.</para>
</listitem>
</varlistentry>
</variablelist>
<para>TODO: explain how to set this up with Java Studio
or Java Studio Creator</para>
<para>The LDAP JavaBeans classes have a <property>
Debug</property> property you can set to have debugging
information displayed. This information is printed
to standard output. TODO: what happens when you use
Java Studio or Creator?</para></sect2><sect2 id="javascript-jdk">
<title>Using the Classes from <trademark>JavaScript
</trademark> Code</title>
<indexterm>
<primary>JavaScript</primary>
</indexterm><indexterm>
<primary>LiveConnect</primary>
</indexterm><indexterm>
<primary>LDAP Java classes</primary>
<secondary>JavaScript and</secondary>
</indexterm><indexterm>
<primary>LDAP Java classes</primary>
<secondary>LiveConnect and</secondary>
</indexterm>
<para>TODO: Update all this. The code doesn't appear
to work with Mozilla.</para>
<para>Using Netscape Communicator's LiveConnect capabilities,
you can use the LDAP Java classes from within JavaScript
code in an HTML page. LiveConnect enables communication
between JavaScript and Java applets in a page and
between JavaScript and plug-ins loaded on a page.
</para>
<para>To see an example of how you can do this, see
the sample JavaScript code in the HTML file in the <filename
class="directory">examples/js</filename> directory.
</para></sect2>-->
</sect1>
</chapter>

View File

@@ -0,0 +1,361 @@
<!--
Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
Portions copyright 1999 Netscape Communications Corporation. All
Rights Reserved.
The contents of this document are subject to the terms of the
Creative Commons Attribution-ShareAlike 2.5 license or any later
version (the "License"). You may not use this document except in
compliance with the License.
See the License for the specific language governing
permissions and limitations under the License. You can obtain
a copy of the License at
http://creativecommons.org/licenses/by-sa/2.5/legalcode.
-->
<chapter id="writing-client"><title>Writing an LDAP Client With &DirectorySDKForJava;</title>
<highlights>
<para>This chapter describes the general process of writing an LDAP client.
The chapter covers the procedures for connecting to an LDAP server. It covers
authentication, requesting operations, and disconnecting from the server. </para>
<itemizedlist>
<para>The chapter covers the following topics:</para>
<listitem><para><olink targetptr="designing-client">Designing an LDAP Java
Client</olink></para></listitem>
<listitem><para><olink targetptr="prepare-client">Creating a Connection and
Setting Preferences With Directory SDK for Java</olink></para></listitem>
<listitem><para><olink targetptr="connect-client">Connecting to an LDAP Server
With Directory SDK for Java</olink></para></listitem>
<listitem><para><olink targetptr="bind-client">Binding and Authenticating
to an LDAP Server With Directory SDK for Java</olink></para></listitem>
<listitem><para><olink targetptr="ldapops-client">Performing LDAP Operations
With Directory SDK for Java</olink></para></listitem>
<listitem><para><olink targetptr="close-client">Closing the Connection to
an LDAP Server With Directory SDK for Java</olink></para></listitem>
</itemizedlist>
</highlights>
<sect1 id="designing-client"><title>Designing an LDAP Java Client</title>
<para>The following steps outline the typical process of communicating with
an LDAP server. Follow these steps when writing your LDAP client.</para>
<orderedlist>
<listitem><para>Create a new <classname>LDAPConnection</classname> object,
and set any preferences that you want applied to all LDAP operations.</para>
</listitem>
<listitem><para>Connect to an LDAP server.</para></listitem>
<listitem><para>If necessary, bind to the LDAP server, specifying the version
of LDAP supported by your client.</para></listitem>
<listitem><para>Perform the LDAP operations, such as searching the directory
or modifying entries in the directory.</para></listitem>
<listitem><para>When finished performing operations, disconnect from the LDAP
server.</para></listitem>
</orderedlist>
<para>The following example LDAP client follows these steps to search a directory.
The client connects to the LDAP server running on the local host at port <literal>
389</literal>. The client then searches the directory for entries with the
surname <literal>Jensen</literal>. Finally, the client displays the DNs of
matching entries.</para>
<programlisting>import netscape.ldap.*;
import java.util.*;
public class Search {
public static void main(String[] args) {
try {
UserArgs userArgs = new UserArgs("Search", args, false);
LDAPConnection ld = new LDAPConnection();
ld.connect(userArgs.getHost(), userArgs.getPort());
/* search for all entries with surname of Jensen */
String MY_FILTER = "sn=Jensen";
String MY_SEARCHBASE = "dc=example,dc=com";
LDAPSearchConstraints cons = ld.getSearchConstraints();
/* Setting the batchSize to one will cause the result
enumeration below to block on one result at a time,
enabling an update of a list or other things as
results come in. */
/* This could be set to 0 in order to get all
results and to block until then. */
cons.setBatchSize(1);
LDAPSearchResults res = ld.search(MY_SEARCHBASE,
LDAPConnection.SCOPE_SUB, MY_FILTER, null, false, cons);
/* Loop on results until finished */
while (res.hasMoreElements()) {
LDAPEntry findEntry = null;
try {
findEntry = res.next();
} catch (LDAPReferralException e) {
System.out.println("Search reference: ");
LDAPUrl refUrls[] = e.getURLs();
for (int i=0; i&lt;refUrls.length; i++) {
System.out.println("\t" + refUrls[i].getUrl());
}
continue;
} catch (LDAPException e) {
System.out.println("Error: " + e.toString());
continue;
}
System.out.println(findEntry.getDN());
/* Get the attributes of the entry */
LDAPAttributeSet findAttrs = findEntry.getAttributeSet();
Enumeration enumAttrs = findAttrs.getAttributes();
System.out.println("\tAttributes: ");
/* Loop on attributes */
while (enumAttrs.hasMoreElements()) {
LDAPAttribute anAttr =
(LDAPAttribute)enumAttrs.nextElement();
String attrName = anAttr.getName();
System.out.println("\t\t" + attrName);
/* Loop on values for this attribute */
Enumeration enumVals = anAttr.getStringValues();
if (enumVals != null) {
while (enumVals.hasMoreElements()) {
String aVal = (String)enumVals.nextElement();
System.out.println("\t\t\t" + aVal);
}
}
}
}
ld.disconnect();
} catch(LDAPException e) {
System.out.println("Error: " + e.toString());
}
}
}</programlisting>
</sect1>
<sect1 id="prepare-client"><title>Creating a Connection and Setting Preferences
With &DirectorySDKForJava;</title>
<indexterm>
<primary>connection</primary>
<secondary>creating</secondary>
</indexterm><indexterm>
<primary>connection</primary>
<secondary>setting preferences</secondary>
</indexterm><indexterm>
<primary>LDAP session</primary>
<secondary>setting preferences</secondary>
</indexterm>
<para>The first step in writing an LDAP client is creating an <classname>LDAPConnection
</classname> object. This object represents the connection to an LDAP server.</para>
<programlisting>LDAPConnection ld = new LDAPConnection();</programlisting>
<note><para>If you plan to connect to the LDAP server over the <firstterm>Secure
Sockets Layer</firstterm> (SSL) protocol, you need to specify a class that
implements SSL sockets. Refer to <olink type="auto-generated" targetptr="ssl">Chapter&nbsp;9,
SSL Connections With Directory SDK for Java</olink> for details.</para></note>
<para>The <classname>LDAPConnection</classname> object also contains preferences
for the LDAP session, such as whether referrals are or are not followed automatically.
To get or set the value of a preference, invoke the <literal>getOption</literal> method
or the <literal>setOption</literal> method as described in the API specification.
</para></sect1>
<sect1 id="connect-client"><title>Connecting to an LDAP Server With &DirectorySDKForJava;</title>
<indexterm>
<primary>LDAP servers</primary>
<secondary>connecting to</secondary>
</indexterm><indexterm>
<primary>LDAP clients</primary>
<secondary>connection to a server</secondary>
</indexterm><indexterm>
<primary>connection</primary>
<secondary>establishing</secondary>
</indexterm><indexterm>
<primary>session</primary>
<secondary>starting</secondary>
</indexterm>
<para>To connect to an LDAP server, use the <literal>connect</literal> method
of the <classname>LDAPConnection</classname> object.</para>
<programlisting>LDAPConnection ld = new LDAPConnection();
ld.connect("ldap.example.com", LDAPv3.DEFAULT_PORT);</programlisting>
<para><literal>DEFAULT_PORT</literal> specifies the default LDAP port, port
389. You can also specify a list of LDAP servers to attempt to connect to.
If the first LDAP server in the list does not respond, the client attempts
to connect to the next server in the list.</para>
<para><indexterm>
<primary>connection</primary>
<secondary>specifying multiple LDAP servers</secondary>
</indexterm><indexterm>
<primary>failover support</primary>
</indexterm>Use a space-delimited list of the host names as the first argument
of the connect method. If the server is not using the default LDAP port, specify
the port number in <replaceable>hostname</replaceable><literal>:</literal><replaceable>
portnumber</replaceable> format.</para>
<programlisting>LDAPConnection ld = new LDAPConnection();
ld.connect("ldap1.example.com ldap2.example.com:3890
ldap3.example.com:3900", LDAPv3.DEFAULT_PORT);</programlisting>
</sect1>
<sect1 id="bind-client"><title>Binding and Authenticating to an LDAP Server
With &DirectorySDKForJava;</title>
<indexterm>
<primary>LDAP clients</primary>
<secondary>authenticating with LDAP servers</secondary>
</indexterm><indexterm>
<primary>LDAP servers</primary>
<secondary>authenticating to</secondary>
</indexterm><indexterm>
<primary>bind operation</primary>
</indexterm>
<para>When connecting to the LDAP server, your client might need to send a
bind operation request to the server. This operation is also called binding
to the server.</para>
<itemizedlist>
<para>An LDAP bind request contains the following information:</para>
<listitem><para>LDAP version of the client</para></listitem>
<listitem><para>DN that is used to authenticate</para></listitem>
<listitem><para>Authentication method that is requested</para></listitem>
<listitem><para>Credentials that are used to authenticate</para></listitem>
</itemizedlist>
<itemizedlist>
<para>The client should send a bind request to the server in the following
situations:</para>
<listitem><para>You want to authenticate to the server.</para><para>For example,
if you want to add or modify entries in the directory, you need to authenticate
as a user with access privileges.</para></listitem>
<listitem><para>You are connecting to an LDAP v2 server.</para><para>LDAP
v2 servers typically require clients to bind before any operations can be
performed.</para></listitem>
</itemizedlist>
<para>An LDAP client can also bind as an anonymous client. For example, the
LDAP server might not require authentication if your client is only searching
the directory.</para>
<para>This section explains how to set up your client to bind to an LDAP server.</para>
<sect2 id="simple-auth-client"><title>Using Simple Authentication</title>
<para>Simple authentication can be used when security is not a concern. If
you plan to use simple authentication, use the <literal>authenticate</literal> method
of the <classname>LDAPConnection</classname> object.</para>
<programlisting>LDAPConnection ld = new LDAPConnection();
ld.connect("ldap.example.com", LDAPv3.DEFAULT_PORT);
ld.authenticate("uid=bjensen,ou=People,cd=example,dc=com", "hifalutin");</programlisting>
<para>The server to which you bind might send back a special control to indicate
that your password has expired. The server might also send back a control
to indicate that your password is to expire in the near future. Refer to <olink
type="auto-generated" targetptr="controls">Chapter&nbsp;10, LDAP Controls
With Directory SDK for Java</olink> for details.</para></sect2>
<sect2 id="anonymous-bind-client"><title>Binding Anonymously</title>
<indexterm>
<primary>anonymous bind</primary>
</indexterm><indexterm>
<primary>binding</primary>
<secondary>anonymously</secondary>
</indexterm>
<para>In some cases, you might not need to authenticate to the LDAP server.
For example, the directory that you search might not require special access
permissions for searches. Therefore, you might not need to authenticate before
performing the search operation. In LDAP v3, the server no longer expects
the client to send a bind request in this type of situation. In LDAP v2, the
server expects the client to send a bind request, even if the operation does
not require the client to authenticate.</para>
<para>In this kind of situation, use the <literal>authenticate</literal> method.
Specify <literal>null</literal> for the DN and password.</para>
<programlisting>LDAPConnection ld = new LDAPConnection();
ld.connect("ldap.example.com", LDAPv3.DEFAULT_PORT);
ld.authenticate(null, null);</programlisting>
</sect2>
<sect2 id="ldap-version-client"><title>Specifying the LDAP Version</title>
<indexterm>
<primary>LDAP clients</primary>
<secondary>specifying protocol version</secondary>
</indexterm>
<para>As part of the bind request sent to the server, the client includes
the version of the LDAP protocol that the client supports. By default, clients
built with the&DirectorySDKForJava; identify themselves as LDAP v2 clients.
Therefore, explicitly identify your client as an LDAP v3 client.</para>
<itemizedlist>
<para>To identify your client as an LDAP v3 client, do one of the following:</para>
<listitem><para>Specify version 3 when invoking the <literal>authenticate</literal> method.
</para>
<programlisting>LDAPConnection ld = new LDAPConnection();
ld.connect("ldap.example.com", LDAPv3.DEFAULT_PORT);
ld.authenticate(3, null, null);</programlisting>
</listitem>
<listitem><para>Invoke the <literal>setOption</literal> method of the <classname>
LDAPConnection</classname> object to set the <literal>LDAPv3.PROTOCOL_VERSION</literal> preference
to <literal>3</literal>, then invoke the <literal>authenticate</literal> method.</para>
<programlisting>LDAPConnection ld = new LDAPConnection();
ld.connect("ldap.example.com", LDAPv3.DEFAULT_PORT);
ld.setOption(LDAPv3.PROTOCOL_VERSION, 3);
ld.authenticate(null, null);</programlisting>
</listitem>
</itemizedlist>
</sect2>
<sect2 id="connect-method-client"><title>Authenticating With the <literal>connect
</literal> Method</title>
<para>The <literal>connect</literal> method of the <classname>LDAPConnection</classname> object
has a signature that allows you to authenticate and specify the LDAP version
supported by your client.</para>
<para>You can specify all of this information using one method, rather than
invoking several methods.</para>
<programlisting>LDAPConnection ld = new LDAPConnection();
ld.connect(3, "ldap.example.com", LDAPv3.DEFAULT_PORT,
&nbsp;&nbsp;&nbsp;&nbsp;"uid=bjensen,ou=People,cd=example,dc=com", "hifalutin");</programlisting>
</sect2>
</sect1>
<sect1 id="ldapops-client"><title>Performing LDAP Operations With &DirectorySDKForJava;</title>
<indexterm>
<primary>LDAP operations</primary>
</indexterm>
<para>First, you initialize a session with an LDAP server. Next, you complete
the authentication process. After authentication, you can perform LDAP operations.
For example, you can search the directory, add new entries, update entries
that exist, and remove entries. You can perform the operations provided that
the server access control allows you to request the operations.</para>
<itemizedlist>
<para>To perform LDAP operations, invoke these methods of the <classname>LDAPConnection
</classname> object:</para>
<listitem><para>To search for entries in the directory, use the <literal>search</literal> method
as explained in <olink targetptr="searching">Chapter&nbsp;4, Searching the
Directory With Directory SDK for Java</olink>.</para></listitem>
<listitem><para>To retrieve a single entry in the directory, use the <literal>read
</literal> method as explained in <olink targetptr="searching">Chapter&nbsp;4,
Searching the Directory With Directory SDK for Java</olink>.</para></listitem>
<listitem><para>To determine whether an attribute contains a certain value,
use the <literal>compare</literal> method as explained in <olink
targetptr="comparing">Chapter&nbsp;6, Comparing Attribute Values With Directory
SDK for Java</olink>.</para></listitem>
<listitem><para>To add entries to the directory, use the <literal>add</literal> method
as explained in <olink targetptr="adding">Chapter&nbsp;5, Adding, Updating,
and Deleting Entries With Directory SDK for Java</olink>.</para></listitem>
<listitem><para>To modify entries in the directory, use the <literal>modify</literal> method
as explained in <olink targetptr="adding">Chapter&nbsp;5, Adding, Updating,
and Deleting Entries With Directory SDK for Java</olink>.</para></listitem>
<listitem><para>To delete entries from the directory, use the <literal>delete</literal> method
as explained in <olink targetptr="adding">Chapter&nbsp;5, Adding, Updating,
and Deleting Entries With Directory SDK for Java</olink>.</para></listitem>
<listitem><para>To rename entries in the directory, use the <literal>rename</literal> method
as explained in <olink targetptr="adding">Chapter&nbsp;5, Adding, Updating,
and Deleting Entries With Directory SDK for Java</olink>.</para></listitem>
</itemizedlist>
</sect1>
<sect1 id="close-client"><title>Closing the Connection to an LDAP Server With &DirectorySDKForJava;</title>
<indexterm>
<primary>ending an LDAP session</primary>
</indexterm><indexterm>
<primary>LDAP session</primary>
<secondary>ending</secondary>
</indexterm><indexterm>
<primary>closing an LDAP connection</primary>
</indexterm><indexterm>
<primary>LDAP servers</primary>
<secondary>closing connection from client</secondary>
</indexterm><indexterm>
<primary>LDAP clients</primary>
<secondary>closing connection to server</secondary>
</indexterm><indexterm>
<primary>connection</primary>
<secondary>closing</secondary>
</indexterm>
<para>When you have finished performing all necessary LDAP operations, close
the connection to the LDAP server. Use the <literal>disconnect</literal> method
of the <classname>LDAPConnection</classname> object to disconnect from the
LDAP server.</para>
<programlisting>LDAPConnection ld = new LDAPConnection();
ld.connect("ldap.example.com", LDAPv3.DEFAULT_PORT);
/*
&nbsp;* Authenticate and perform LDAP operations.
&nbsp;*/
ld.disconnect();</programlisting>
</sect1>
</chapter>

View File

@@ -0,0 +1,113 @@
<!--
Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
Portions copyright 1999 Netscape Communications Corporation. All
Rights Reserved.
The contents of this document are subject to the terms of the
Creative Commons Attribution-ShareAlike 2.5 license or any later
version (the "License"). You may not use this document except in
compliance with the License.
See the License for the specific language governing
permissions and limitations under the License. You can obtain
a copy of the License at
http://creativecommons.org/licenses/by-sa/2.5/legalcode.
-->
<para>Copyright 2000-2007 Sun Microsystems, Inc., 4150 Network Circle,
Santa Clara, California 95054, U.S.A. All rights reserved. Portions
copyright 1999 Netscape Communications Corporations. All rights
reserved.</para>
<para>Sun Microsystems, Inc. has intellectual property rights relating
to technology embodied in the product that is described in this
document. In particular, and without limitation, these intellectual
property rights may include one or more U.S. patents or pending patent
applications in the U.S. and in other countries.</para>
<para>U.S. Government Rights - Commercial software. Government users
are subject to the Sun Microsystems, Inc. standard license agreement
and applicable provisions of the FAR and its supplements.</para>
<para>This distribution may include materials developed by third
parties.</para>
<para>Parts of the product may be derived from Berkeley BSD systems,
licensed from the University of California. UNIX is a registered
trademark in the U.S. and in other countries, exclusively licensed
through X/Open Company, Ltd.</para>
<para>Sun, Sun Microsystems, the Sun logo, Java, Solaris, JavaBeans,
JavaScript and the SunTone Certified logo are trademarks or registered
trademarks of Sun Microsystems, Inc. in the U.S. and other
countries.</para>
<para>All SPARC trademarks are used under license and are trademarks
or registered trademarks of SPARC International, Inc. in the U.S. and
other countries. Products bearing SPARC trademarks are based upon
architecture developed by Sun Microsystems, Inc.</para>
<para>Mozilla, Netscape, and Netscape Navigator are trademarks or
registered trademarks of Netscape Communications Corporation in the
United States and other countries.</para>
<para>Products covered by and information contained in this service
manual are controlled by U.S. Export Control laws and may be subject
to the export or import laws in other countries. Nuclear, missile,
chemical biological weapons or nuclear maritime end uses or end users,
whether direct or indirect, are strictly prohibited. Export or
reexport to countries subject to U.S. embargo or to entities
identified on U.S. export exclusion lists, including, but not limited
to, the denied persons and specially designated nationals lists is
strictly prohibited.</para>
<para>DOCUMENTATION IS PROVIDED &ldquo;AS IS&rdquo; AND ALL EXPRESS OR
IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
OR NON-INFRINGEMENT, ARE DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH
DISCLAIMERS ARE HELD TO BE LEGALLY INVALID.</para>
<para>Copyright 2000-2007 Sun Microsystems, Inc., 4150 Network Circle,
Santa Clara, California 95054, Etats-Unis. Tous droits
r&eacute;serv&eacute;s. Certaines parties copyright 1999 Netscape
Communications Corporations. Tous droits r&eacute;serv&eacute;s.</para>
<para>Sun Microsystems, Inc. d&eacute;tient les droits de
propri&eacute;t&eacute; intellectuelle relatifs &agrave; la
technologie incorpor&eacute;e dans le produit qui est d&eacute;crit
dans ce document. En particulier, et ce sans limitation, ces droits de
propri&eacute;t&eacute; intellectuelle peuvent inclure un ou plusieurs
brevets am&eacute;ricains ou des applications de brevet en attente aux
Etats-Unis et dans d'autres pays.</para>
<para>Cette distribution peut comprendre des composants
d&eacute;velopp&eacute;s par des tierces parties.</para>
<para>Des parties de ce produit pourront &ecirc;tre
d&eacute;riv&eacute;es des syst&egrave;mes Berkeley BSD
licenci&eacute;s par l'Universit&eacute; de Californie. UNIX est une
marque d&eacute;pos&eacute;e aux Etats-Unis et dans d'autres pays et
licenci&eacute;e exclusivement par X/Open Company, Ltd.</para>
<para>Sun, Sun Microsystems, le logo Sun, Java, Solaris, JavaBeans,
JavaScript et le logo SunTone Certified sont des marques de fabrique
ou des marques d&eacute;pos&eacute;es de Sun Microsystems, Inc. aux
Etats-Unis et dans d'autres pays.</para>
<para>Toutes les marques SPARC sont utilis&eacute;es sous licence et
sont des marques de fabrique ou des marques d&eacute;pos&eacute;es de
SPARC International, Inc. aux Etats-Unis et dans d'autres pays. Les
produits portant les marques SPARC sont bas&eacute;s sur une
architecture d&eacute;velopp&eacute;e par Sun Microsystems,
Inc.</para>
<para>Mozilla, Netscape, et Netscape Navigator sont des marques de
Netscape Communications Corporation aux Etats-Unis et dans d'autres
pays.</para>
<para>Les produits qui font l'objet de ce manuel d'entretien et les
informations qu'il contient sont regis par la legislation americaine
en matiere de controle des exportations et peuvent etre soumis au
droit d'autres pays dans le domaine des exportations et
importations. Les utilisations finales, ou utilisateurs finaux, pour
des armes nucleaires, des missiles, des armes biologiques et chimiques
ou du nucleaire maritime, directement ou indirectement, sont
strictement interdites. Les exportations ou reexportations vers des
pays sous embargo des Etats-Unis, ou vers des entites figurant sur les
listes d'exclusion d'exportation americaines, y compris, mais de
maniere non exclusive, la liste de personnes qui font objet d'un ordre
de ne pas participer, d'une facon directe ou indirecte, aux
exportations des produits ou des services qui sont regi par la
legislation americaine en matiere de controle des exportations et la
liste de ressortissants specifiquement designes, sont rigoureusement
interdites.</para>
<para>LA DOCUMENTATION EST FOURNIE &ldquo;EN L'ETAT&rdquo; ET TOUTES
AUTRES CONDITIONS, DECLARATIONS ET GARANTIES EXPRESSES OU TACITES SONT
FORMELLEMENT EXCLUES, DANS LA MESURE AUTORISEE PAR LA LOI APPLICABLE,
Y COMPRIS NOTAMMENT TOUTE GARANTIE IMPLICITE RELATIVE A LA QUALITE
MARCHANDE, A L'APTITUDE A UNE UTILISATION PARTICULIERE OU A L'ABSENCE
DE CONTREFACON. </para>

View File

@@ -0,0 +1,226 @@
Attribution-ShareAlike 2.5
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL
SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN ATTORNEY-CLIENT
RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS.
CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE INFORMATION PROVIDED, AND
DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM ITS USE.
License
THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS
PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR
OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS
LICENSE OR COPYRIGHT LAW IS PROHIBITED.
BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE
BOUND BY THE TERMS OF THIS LICENSE. THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED
HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS.
1. Definitions
1. "Collective Work" means a work, such as a periodical issue, anthology or
encyclopedia, in which the Work in its entirety in unmodified form, along with a
number of other contributions, constituting separate and independent works in
themselves, are assembled into a collective whole. A work that constitutes a
Collective Work will not be considered a Derivative Work (as defined below) for
the purposes of this License.
2. "Derivative Work" means a work based upon the Work or upon the Work and
other pre-existing works, such as a translation, musical arrangement,
dramatization, fictionalization, motion picture version, sound recording, art
reproduction, abridgment, condensation, or any other form in which the Work may
be recast, transformed, or adapted, except that a work that constitutes a
Collective Work will not be considered a Derivative Work for the purpose of this
License. For the avoidance of doubt, where the Work is a musical composition or
sound recording, the synchronization of the Work in timed-relation with a moving
image ("synching") will be considered a Derivative Work for the purpose of this
License.
3. "Licensor" means the individual or entity that offers the Work under the
terms of this License.
4. "Original Author" means the individual or entity who created the Work.
5. "Work" means the copyrightable work of authorship offered under the terms
of this License.
6. "You" means an individual or entity exercising rights under this License
who has not previously violated the terms of this License with respect to the
Work, or who has received express permission from the Licensor to exercise
rights under this License despite a previous violation.
7. "License Elements" means the following high-level license attributes as
selected by Licensor and indicated in the title of this License: Attribution,
ShareAlike.
2. Fair Use Rights. Nothing in this license is intended to reduce, limit, or
restrict any rights arising from fair use, first sale or other limitations on
the exclusive rights of the copyright owner under copyright law or other
applicable laws.
3. License Grant. Subject to the terms and conditions of this License, Licensor
hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the
duration of the applicable copyright) license to exercise the rights in the Work
as stated below:
1. to reproduce the Work, to incorporate the Work into one or more Collective
Works, and to reproduce the Work as incorporated in the Collective Works;
2. to create and reproduce Derivative Works;
3. to distribute copies or phonorecords of, display publicly, perform
publicly, and perform publicly by means of a digital audio transmission the Work
including as incorporated in Collective Works;
4. to distribute copies or phonorecords of, display publicly, perform
publicly, and perform publicly by means of a digital audio transmission
Derivative Works.
5.
For the avoidance of doubt, where the work is a musical composition:
1. Performance Royalties Under Blanket Licenses. Licensor waives the
exclusive right to collect, whether individually or via a performance rights
society (e.g. ASCAP, BMI, SESAC), royalties for the public performance or public
digital performance (e.g. webcast) of the Work.
2. Mechanical Rights and Statutory Royalties. Licensor waives the
exclusive right to collect, whether individually or via a music rights society
or designated agent (e.g. Harry Fox Agency), royalties for any phonorecord You
create from the Work ("cover version") and distribute, subject to the compulsory
license created by 17 USC Section 115 of the US Copyright Act (or the equivalent
in other jurisdictions).
6. Webcasting Rights and Statutory Royalties. For the avoidance of doubt,
where the Work is a sound recording, Licensor waives the exclusive right to
collect, whether individually or via a performance-rights society (e.g.
SoundExchange), royalties for the public digital performance (e.g. webcast) of
the Work, subject to the compulsory license created by 17 USC Section 114 of the
US Copyright Act (or the equivalent in other jurisdictions).
The above rights may be exercised in all media and formats whether now known or
hereafter devised. The above rights include the right to make such modifications
as are technically necessary to exercise the rights in other media and formats.
All rights not expressly granted by Licensor are hereby reserved.
4. Restrictions.The license granted in Section 3 above is expressly made subject
to and limited by the following restrictions:
1. You may distribute, publicly display, publicly perform, or publicly
digitally perform the Work only under the terms of this License, and You must
include a copy of, or the Uniform Resource Identifier for, this License with
every copy or phonorecord of the Work You distribute, publicly display, publicly
perform, or publicly digitally perform. You may not offer or impose any terms on
the Work that alter or restrict the terms of this License or the recipients'
exercise of the rights granted hereunder. You may not sublicense the Work. You
must keep intact all notices that refer to this License and to the disclaimer of
warranties. You may not distribute, publicly display, publicly perform, or
publicly digitally perform the Work with any technological measures that control
access or use of the Work in a manner inconsistent with the terms of this
License Agreement. The above applies to the Work as incorporated in a Collective
Work, but this does not require the Collective Work apart from the Work itself
to be made subject to the terms of this License. If You create a Collective
Work, upon notice from any Licensor You must, to the extent practicable, remove
from the Collective Work any credit as required by clause 4(c), as requested. If
You create a Derivative Work, upon notice from any Licensor You must, to the
extent practicable, remove from the Derivative Work any credit as required by
clause 4(c), as requested.
2. You may distribute, publicly display, publicly perform, or publicly
digitally perform a Derivative Work only under the terms of this License, a
later version of this License with the same License Elements as this License, or
a Creative Commons iCommons license that contains the same License Elements as
this License (e.g. Attribution-ShareAlike 2.5 Japan). You must include a copy
of, or the Uniform Resource Identifier for, this License or other license
specified in the previous sentence with every copy or phonorecord of each
Derivative Work You distribute, publicly display, publicly perform, or publicly
digitally perform. You may not offer or impose any terms on the Derivative Works
that alter or restrict the terms of this License or the recipients' exercise of
the rights granted hereunder, and You must keep intact all notices that refer to
this License and to the disclaimer of warranties. You may not distribute,
publicly display, publicly perform, or publicly digitally perform the Derivative
Work with any technological measures that control access or use of the Work in a
manner inconsistent with the terms of this License Agreement. The above applies
to the Derivative Work as incorporated in a Collective Work, but this does not
require the Collective Work apart from the Derivative Work itself to be made
subject to the terms of this License.
3. If you distribute, publicly display, publicly perform, or publicly
digitally perform the Work or any Derivative Works or Collective Works, You must
keep intact all copyright notices for the Work and provide, reasonable to the
medium or means You are utilizing: (i) the name of the Original Author (or
pseudonym, if applicable) if supplied, and/or (ii) if the Original Author and/or
Licensor designate another party or parties (e.g. a sponsor institute,
publishing entity, journal) for attribution in Licensor's copyright notice,
terms of service or by other reasonable means, the name of such party or
parties; the title of the Work if supplied; to the extent reasonably
practicable, the Uniform Resource Identifier, if any, that Licensor specifies to
be associated with the Work, unless such URI does not refer to the copyright
notice or licensing information for the Work; and in the case of a Derivative
Work, a credit identifying the use of the Work in the Derivative Work (e.g.,
"French translation of the Work by Original Author," or "Screenplay based on
original Work by Original Author"). Such credit may be implemented in any
reasonable manner; provided, however, that in the case of a Derivative Work or
Collective Work, at a minimum such credit will appear where any other comparable
authorship credit appears and in a manner at least as prominent as such other
comparable authorship credit.
5. Representations, Warranties and Disclaimer
UNLESS OTHERWISE AGREED TO BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK
AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE
MATERIALS, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT
LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR
PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY,
OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME
JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH
EXCLUSION MAY NOT APPLY TO YOU.
6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN
NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL,
INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS
LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
7. Termination
1. This License and the rights granted hereunder will terminate automatically
upon any breach by You of the terms of this License. Individuals or entities who
have received Derivative Works or Collective Works from You under this License,
however, will not have their licenses terminated provided such individuals or
entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7,
and 8 will survive any termination of this License.
2. Subject to the above terms and conditions, the license granted here is
perpetual (for the duration of the applicable copyright in the Work).
Notwithstanding the above, Licensor reserves the right to release the Work under
different license terms or to stop distributing the Work at any time; provided,
however that any such election will not serve to withdraw this License (or any
other license that has been, or is required to be, granted under the terms of
this License), and this License will continue in full force and effect unless
terminated as stated above.
8. Miscellaneous
1. Each time You distribute or publicly digitally perform the Work or a
Collective Work, the Licensor offers to the recipient a license to the Work on
the same terms and conditions as the license granted to You under this License.
2. Each time You distribute or publicly digitally perform a Derivative Work,
Licensor offers to the recipient a license to the original Work on the same
terms and conditions as the license granted to You under this License.
3. If any provision of this License is invalid or unenforceable under
applicable law, it shall not affect the validity or enforceability of the
remainder of the terms of this License, and without further action by the
parties to this agreement, such provision shall be reformed to the minimum
extent necessary to make such provision valid and enforceable.
4. No term or provision of this License shall be deemed waived and no breach
consented to unless such waiver or consent shall be in writing and signed by the
party to be charged with such waiver or consent.
5. This License constitutes the entire agreement between the parties with
respect to the Work licensed here. There are no understandings, agreements or
representations with respect to the Work not specified here. Licensor shall not
be bound by any additional provisions that may appear in any communication from
You. This License may not be modified without the mutual written agreement of
the Licensor and You.
Creative Commons is not a party to this License, and makes no warranty
whatsoever in connection with the Work. Creative Commons will not be liable to
You or any party on any legal theory for any damages whatsoever, including
without limitation any general, special, incidental or consequential damages
arising in connection to this license. Notwithstanding the foregoing two (2)
sentences, if Creative Commons has expressly identified itself as the Licensor
hereunder, it shall have all rights and obligations of Licensor.
Except for the limited purpose of indicating to the public that the Work is
licensed under the CCPL, neither party will use the trademark "Creative Commons"
or any related trademark or logo of Creative Commons without the prior written
consent of Creative Commons. Any permitted use will be in compliance with
Creative Commons' then-current trademark usage guidelines, as may be published
on its website or otherwise made available upon request from time to time.
Creative Commons may be contacted at http://creativecommons.org/.

View File

@@ -0,0 +1,349 @@
<!--
Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
Portions copyright 1999 Netscape Communications Corporation. All
Rights Reserved.
The contents of this document are subject to the terms of the
Creative Commons Attribution-ShareAlike 2.5 license or any later
version (the "License"). You may not use this document except in
compliance with the License.
See the License for the specific language governing
permissions and limitations under the License. You can obtain
a copy of the License at
http://creativecommons.org/licenses/by-sa/2.5/legalcode.
-->
<preface id="preface"><title>Preface</title>
<highlights>&abstract;
</highlights>
<sect1 id="who-should-read"><title>Who Should Use This Book</title>
<para>This guide is intended for developers creating directory client applications.
</para>
<itemizedlist>
<para>Before using this guide, you must be familiar with the following:</para>
<listitem><para>&cnDirectoryServer; functionality</para></listitem>
<listitem><para>Developing programs in the <trademark>Java</trademark> programming
language</para></listitem>
<listitem><para>Specifications for LDAP and related protocols, such as DSML
v2</para></listitem>
<listitem><para>Internet and World Wide Web technologies</para></listitem>
</itemizedlist>
</sect1>
<sect1 id="before-you-read"><title>Before You Read This Book</title>
<para>Before developing directory client applications, install &DirectorySDKForJava;.
</para>
<!-- TODO: Need an XREF to installation instructions -->
</sect1>
<sect1 id="reading-for-developers"><title>Additional Recommended Reading</title>
<itemizedlist>
<para>Directory client application developers might benefit from reading the
following books:</para>
<listitem><para><citetitle>LDAP Programming with Java</citetitle> by Weltman
and Dabhura (ISBN 0-201-65758-96)</para></listitem>
<listitem><para><citetitle>LDAP Programming, Management and Integration</citetitle> by
Donley (ISBN 1930110405)</para></listitem>
<listitem><para><citetitle>LDAP: Programming Directory-Enabled Applications
with Lightweight Directory Access Protocol</citetitle> by Howes and Smith
(ISBN 1-57870-000-00)</para></listitem>
<listitem><para><citetitle>Understanding and Deploying LDAP Directory Services</citetitle> by
Howes, et al. (ISBN 1-57870-070-10)</para></listitem>
</itemizedlist>
<itemizedlist>
<para>In addition, keep bookmarks to the following IETF documents:</para>
<listitem><para><ulink url="http://www.ietf.org/rfc/rfc2251.txt" type="text_url">
RFC 2251</ulink>, <citetitle>Lightweight Directory Access Protocol (v3)</citetitle></para>
</listitem>
<listitem><para><ulink url="http://www.ietf.org/rfc/rfc2252.txt" type="text_url">
RFC 2252</ulink>, <citetitle>Lightweight Directory Access Protocol (v3): Attribute
Syntax Definitions</citetitle></para></listitem>
<listitem><para><ulink url="http://www.ietf.org/rfc/rfc2253.txt" type="text_url">
RFC 2253</ulink>, <citetitle>Lightweight Directory Access Protocol (v3): UTF-8
String Representation of Distinguished Names</citetitle></para></listitem>
<listitem><para><ulink url="http://www.ietf.org/rfc/rfc2254.txt" type="text_url">
RFC 2254</ulink>, <citetitle>The String Representation of LDAP Search Filters</citetitle></para>
</listitem>
<listitem><para><ulink url="http://www.ietf.org/rfc/rfc2255.txt" type="text_url">
RFC 2255</ulink>, <citetitle>The LDAP URL Format</citetitle></para></listitem>
<listitem><para><ulink url="http://www.ietf.org/rfc/rfc2256.txt" type="text_url">
RFC 2256</ulink>, <citetitle>A Summary of the X.500(96) User Schema for use
with LDAPv3</citetitle></para></listitem>
<listitem><para><ulink url="http://www.ietf.org/rfc/rfc2829.txt" type="text_url">
RFC 2829</ulink>, <citetitle>Authentication Methods for LDAP</citetitle></para>
</listitem>
<listitem><para><ulink url="http://www.ietf.org/rfc/rfc2830.txt" type="text_url">
RFC 2830</ulink>, <citetitle>Lightweight Directory Access Protocol (v3): Extension
for Transport Layer Security</citetitle></para></listitem>
<listitem><para><ulink url="http://www.ietf.org/rfc/rfc2849.txt" type="text_url">
RFC 2849</ulink>, <citetitle>The LDAP Data Interchange Format (LDIF) - Technical
Specification</citetitle></para></listitem>
<listitem><para><ulink url="http://www.ietf.org/rfc/rfc3377.txt" type="text_url">
RFC 3377</ulink>, <citetitle>Lightweight Directory Access Protocol (v3): Technical
Specification</citetitle></para></listitem>
</itemizedlist>
</sect1>
<sect1 id="organization"><title>How This Book Is Organized</title>
<itemizedlist>
<para>This guide includes the following chapters.</para>
<listitem><para><olink targetptr="understanding-ldap">Chapter&nbsp;1, Understanding LDAP</olink> describes LDAP and directory concepts.</para></listitem>
<listitem><para><olink targetptr="best-practices-choose">Chapter&nbsp;2, Choosing a Client SDK</olink> covers what to consider when choosing a software development kit for building directory client applications.</para></listitem>
<listitem><para><olink targetptr="best-practices-overview">Chapter&nbsp;3,
Best Practices for Writing Client Applications</olink> reviews what and what
not to do when building directory client applications.</para></listitem>
<listitem><para><olink targetptr="quickstart-jdk">Chapter&nbsp;1, Getting
Started With Directory SDK for Java</olink> gets you started using &DirectorySDKForJava;</para>
</listitem>
<listitem><para><olink targetptr="writing-client">Chapter&nbsp;2, Writing an LDAP Client With Directory SDK for Java</olink> covers the basics of writing
a directory client application</para></listitem>
<listitem><para><olink targetptr="common-classes">Chapter&nbsp;3, Using the LDAP Java Classes</olink> provides a look how &DirectorySDKForJava; is
structured</para></listitem>
<listitem><para><olink targetptr="searching">Chapter&nbsp;4, Searching the Directory With Directory SDK for Java</olink> shows you how to write client
application code for searching a directory</para></listitem>
<!--<listitem><para><olink targetptr="filter-conf"></olink> shows you
how to write client application code for searching
a directory using filter configuration files</para>
</listitem>-->
<listitem><para><olink targetptr="adding">Chapter&nbsp;5, Adding, Updating, and Deleting Entries With Directory SDK for Java</olink> shows you how to
write client application code for changing directory entries</para></listitem>
<listitem><para><olink targetptr="comparing">Chapter&nbsp;6, Comparing Attribute Values With Directory SDK for Java</olink> shows you how to comparing attribute
values in a directory with known values</para></listitem>
<listitem><para><olink targetptr="ldap-urls">Chapter&nbsp;7, LDAP URLs With Directory SDK for Java</olink> shows you how to handle LDAP URLs</para>
</listitem>
<listitem><para><olink targetptr="server-info">Chapter&nbsp;8, Getting Server Information With Directory SDK for Java</olink> shows you how to retrieve
information about the directory and directory service</para></listitem>
<listitem><para><olink targetptr="ssl">Chapter&nbsp;9, SSL Connections With Directory SDK for Java</olink> shows you how to write client application code
that connects to the directory over SSL</para></listitem>
<listitem><para><olink targetptr="controls">Chapter&nbsp;10, LDAP Controls With Directory SDK for Java</olink> shows you how to handle supported LDAP
controls</para></listitem>
<listitem><para><olink targetptr="sasl">Chapter&nbsp;11, SASL Authentication With Directory SDK for Java</olink> shows you how to connect to the directory
by using SASL</para></listitem>
<listitem><para><olink targetptr="extended-ops">Chapter&nbsp;12, Extended Operations With Directory SDK for Java</olink> shows you how to write client
application code for handling LDAP v3 extended operations</para></listitem>
<listitem><para><olink targetptr="asynchronous">Chapter&nbsp;13, Writing Asynchronous Clients With Directory SDK for Java</olink> shows you how to write applications
that do not block waiting for results</para></listitem>
<listitem><para><olink targetptr="share-alike">Appendix A, Creative Commons Attribution-ShareAlike 2.5</olink> provides the full text of the license governing this guide</para>
</listitem>
</itemizedlist>
</sect1>
<sect1 id="related-reading"><title>Related Reading</title>
<para><indexterm>
<primary>SLAMD Distributed Load Generation Engine</primary>
</indexterm>The SLAMD Distributed Load Generation Engine (SLAMD) is a <trademark>
Java</trademark> application that is designed to stress test and analyze the
performance of network-based applications. It was originally developed by
Sun Microsystems, Inc. to benchmark and analyze the performance of LDAP directory
servers. SLAMD is available as an open source application under the Sun Public
License, an OSI-approved open source license. To obtain information about
SLAMD, go to <ulink url="http://www.slamd.com/" type="url"></ulink>. SLAMD
is also available as a java.net project. See <ulink
url="https://slamd.dev.java.net/" type="url"></ulink>.</para>
<para><indexterm>
<primary>Java Naming and Directory Interface</primary>
</indexterm>Java Naming and Directory Interface (JNDI) technology supports
accessing the Directory Server using LDAP and DSML v2 from Java applications.
For information about JNDI, see <ulink url="http://java.sun.com/products/jndi/"
type="url"></ulink>. The <citetitle>JNDI Tutorial</citetitle> contains detailed
descriptions and examples of how to use JNDI. This tutorial is at <ulink
url="http://java.sun.com/products/jndi/tutorial/" type="url"></ulink>.</para>
</sect1>
<sect1 id="FWBKX"><title>Typographic Conventions</title>
<para>The following table describes the typographic changes that are used
in this book.</para>
<table frame="topbot" id="FWBTE"><title>Typographic Conventions</title>
<tgroup cols="3" colsep="0" rowsep="0"><colspec colwidth="15*"><colspec
colwidth="40*"><colspec colwidth="45*">
<thead>
<row rowsep="1">
<entry align="left">
<para>Typeface</para></entry>
<entry align="left">
<para>Meaning</para></entry>
<entry align="left">
<para>Example</para></entry>
</row>
</thead>
<tbody>
<row>
<entry>
<para><literal>AaBbCc123</literal></para></entry>
<entry>
<para>The names of commands, files, and directories, and onscreen computer
output</para></entry>
<entry>
<para>Edit your <filename>.login</filename> file.</para>
<para>Use <command>ls <option>a</option></command> to list all files.</para>
<para><computeroutput>machine_name% you have mail.</computeroutput></para>
</entry>
</row>
<row>
<entry>
<para><userinput>AaBbCc123</userinput></para></entry>
<entry>
<para>What you type, contrasted with onscreen computer output</para></entry>
<entry>
<para><computeroutput>machine_name%</computeroutput> <userinput>su</userinput></para>
<para><computeroutput>Password:</computeroutput></para></entry>
</row>
<row>
<entry>
<para><replaceable>AaBbCc123</replaceable></para></entry>
<entry>
<para>A placeholder to be replaced with a real name or value</para></entry>
<entry>
<para>The command to remove a file is <command>rm</command> <replaceable>filename
</replaceable>.</para></entry>
</row>
<row>
<entry>
<para><emphasis>AaBbCc123</emphasis></para></entry>
<entry>
<para>Book titles, new terms, and terms to be emphasized (note that some emphasized
items appear bold online)</para></entry>
<entry>
<para>Read Chapter 6 in the <citetitle>User's Guide</citetitle>.</para>
<para>A <emphasis>cache</emphasis> is a copy that is stored locally.</para>
<para>Do <emphasis>not</emphasis> save the file.</para></entry>
</row>
</tbody>
</tgroup>
</table>
</sect1>
<sect1 id="FWBMK"><title>Shell Prompts in Command Examples</title>
<para>The following table shows default system prompts and superuser prompts.</para>
<table frame="topbot" id="GCTTT"><title>Shell Prompts</title>
<tgroup cols="2" colsep="0" rowsep="0"><colspec colwidth="75*"><colspec
colwidth="25*">
<thead>
<row rowsep="1">
<entry>
<para>Shell</para></entry>
<entry>
<para>Prompt</para></entry>
</row>
</thead>
<tbody>
<row>
<entry>
<para>C shell on UNIX and Linux systems</para></entry>
<entry>
<para><literal>machine_name%</literal></para></entry>
</row>
<row>
<entry>
<para>C shell superuser on UNIX and Linux systems</para></entry>
<entry>
<para><literal>machine_name#</literal></para></entry>
</row>
<row>
<entry>
<para>Bourne shell and Korn shell on UNIX and Linux systems</para></entry>
<entry>
<para><literal>$</literal></para></entry>
</row>
<row>
<entry>
<para>Bourne shell and Korn shell superuser on UNIX and Linux systems</para>
</entry>
<entry>
<para><literal>#</literal></para></entry>
</row>
<row>
<entry>
<para>Microsoft Windows command line</para></entry>
<entry>
<para><literal>C:\</literal></para></entry>
</row>
</tbody>
</tgroup>
</table>
</sect1>
<sect1 id="FQUVC"><title>Symbol Conventions</title>
<para>The following table explains symbols that might be used in this book.</para>
<table frame="topbot" id="FQUVR"><title>Symbol Conventions</title>
<tgroup cols="4" colsep="0" rowsep="0"><colspec colnum="1" colwidth="8*"
align="center"><colspec colnum="2" colwidth="28*"><colspec colnum="3"
colwidth="28*"><colspec colnum="4" colwidth="36*">
<thead>
<row rowsep="1">
<entry>
<para>Symbol</para></entry>
<entry>
<para>Description</para></entry>
<entry>
<para>Example</para></entry>
<entry>
<para>Meaning</para></entry>
</row>
</thead>
<tbody>
<row>
<entry>
<para><literal>[ ]</literal></para></entry>
<entry>
<para>Contains optional arguments and command options.</para></entry>
<entry>
<para><literal>ls [-l]</literal></para></entry>
<entry>
<para>The <literal>-l</literal> option is not required.</para></entry>
</row>
<row>
<entry>
<para><literal>{ | }</literal></para></entry>
<entry>
<para>Contains a set of choices for a required command option.</para></entry>
<entry>
<para><literal>-d {y|n}</literal></para></entry>
<entry>
<para>The <literal>-d</literal> option requires that you use either the <literal>
y</literal> argument or the <literal>n</literal> argument.</para></entry>
</row>
<row>
<entry>
<para><literal>${ }</literal></para></entry>
<entry>
<para>Indicates a variable reference.</para></entry>
<entry>
<para><literal>${com.sun.javaRoot}</literal></para></entry>
<entry>
<para>References the value of the <literal>com.sun.javaRoot</literal> variable.</para>
</entry>
</row>
<row>
<entry>
<para>-</para></entry>
<entry>
<para>Joins simultaneous multiple keystrokes.</para></entry>
<entry>
<para>Control-A</para></entry>
<entry>
<para>Press the Control key while you press the A key.</para></entry>
</row>
<row>
<entry>
<para>+</para></entry>
<entry>
<para>Joins consecutive multiple keystrokes.</para></entry>
<entry>
<para>Ctrl+A+N</para></entry>
<entry>
<para>Press the Control key, release it, and then press the subsequent keys.</para>
</entry>
</row>
<row>
<entry>
<para>&rarr;</para></entry>
<entry>
<para>Indicates menu item selection in a graphical user interface.</para>
</entry>
<entry>
<para>File &rarr; New &rarr; Templates</para></entry>
<entry>
<para>From the File menu, choose New. From the New submenu, choose Templates.</para>
</entry>
</row>
</tbody>
</tgroup>
</table>
</sect1>
</preface>

View File

@@ -0,0 +1,274 @@
<!--
Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
Portions copyright 1999 Netscape Communications Corporation. All
Rights Reserved.
The contents of this document are subject to the terms of the
Creative Commons Attribution-ShareAlike 2.5 license or any later
version (the "License"). You may not use this document except in
compliance with the License.
See the License for the specific language governing
permissions and limitations under the License. You can obtain
a copy of the License at
http://creativecommons.org/licenses/by-sa/2.5/legalcode.
-->
<chapter id="understanding-ldap"><title>Understanding LDAP</title>
<indexterm>
<primary>LDAP</primary>
</indexterm><indexterm>
<primary>Lightweight Directory Access Protocol</primary>
<see>LDAP</see></indexterm><highlights>
<para><firstterm>Lightweight Directory Access Protocol</firstterm> (LDAP)
is the Internet directory protocol. Developed at the University of Michigan
at Ann Arbor in conjunction with the Internet Engineering Task Force, LDAP
is a protocol for accessing and managing directory services.</para>
<itemizedlist>
<para>This chapter explains the LDAP protocol, and the concepts behind LDAP.
This chapter covers the following topics:</para>
<listitem><para><olink targetptr="how-ds-works">How Directory Services Work</olink></para>
</listitem>
<listitem><para><olink targetptr="how-ds-organizes-data">How LDAP Servers
Organize Directories</olink></para></listitem>
<listitem><para><olink targetptr="how-ldap-clients-servers-work">How LDAP
Clients and Servers Work</olink></para></listitem>
<listitem><para><olink targetptr="understanding-ldapv3">Understanding LDAP
v3</olink></para></listitem>
</itemizedlist>
</highlights>
<sect1 id="how-ds-works"><title>How Directory Services Work</title>
<indexterm>
<primary>directory</primary>
<secondary>definition of</secondary>
</indexterm><indexterm>
<primary>entries</primary>
<secondary>definition of</secondary>
</indexterm><indexterm>
<primary>attributes</primary>
<secondary>definition of</secondary>
</indexterm>
<para>A <firstterm>directory</firstterm> consists of <firstterm>entries</firstterm> that
contain descriptive information. For example, a directory might contain entries
that describe people or network resources, such as printers or fax machines.</para>
<para>The descriptive information is stored in the <firstterm>attributes</firstterm> of
the entry. Each attribute describes a specific type of information. For example,
attributes that describe a person might include her name, also referred to
as her common name (CN), telephone number, and email address.</para>
<para><indexterm>
<primary>entries</primary>
<secondary>example of</secondary>
</indexterm><indexterm>
<primary>attributes</primary>
<secondary>example of</secondary>
</indexterm>The entry for <literal>Barbara Jensen</literal> might have the
following attributes:</para>
<programlisting>cn: Barbara Jensen
mail: babs@example.com
telephoneNumber: 555-1212
roomNumber: 3995</programlisting>
<para>An attribute can have more than one value. For example, a person might
have two common names, both a formal name and also a nickname:</para>
<programlisting>cn: Barbara Jensen
cn: Babs Jensen
mail: babs@example.com
telephoneNumber: 555-1212
roomNumber: 3995</programlisting>
<para>Attributes can also contain binary data. For example, a person's attributes
might include her photo in JPEG format, a recording of her voice as an audio
file, or her SSL certificate.</para>
<para><indexterm>
<primary>directory service</primary>
<secondary>definition of</secondary>
</indexterm>A <firstterm>directory service</firstterm> is a distributed database
application for managing the entries and attributes in a directory. A directory
service also makes the entries and attributes available to users and other
applications.</para>
<para>&cnDirectoryServer; is an example of a directory service. For example,
a user might use the directory service to look up someone's telephone number.
Another application might use the directory service to retrieve a list of
email addresses.</para>
<para><indexterm>
<primary>LDAP servers</primary>
</indexterm><indexterm>
<primary>LDAP clients</primary>
</indexterm>LDAP is a protocol that defines a directory service and access
to that service. LDAP is based on a client-server model. LDAP servers provide
the directory service. LDAP clients use the directory service to access entries
and attributes.</para>
<para><indexterm>
<primary>LDAP servers</primary>
<secondary>example of</secondary>
</indexterm><indexterm>
<primary>LDAP clients</primary>
<secondary>example of</secondary>
</indexterm>&cnDirectoryServer; is an example of an LDAP server that manages
and provides information about users and organizational structures. Examples
of LDAP clients include Identity Manager, Access Manager, <trademark>Solaris</trademark> naming
services, Messaging Server, Portal Server, NameFinder, and the Mozilla mail
client. Such clients use &cnDirectoryServer; to find, update, and add information
about users.</para></sect1>
<sect1 id="how-ds-organizes-data"><title>How LDAP Servers Organize Directories</title>
<indexterm>
<primary>LDAP</primary>
<secondary>organization of data</secondary>
</indexterm><indexterm>
<primary>entries</primary>
<secondary>organization in LDAP</secondary>
</indexterm><indexterm>
<primary>LDAP servers</primary>
<secondary>how data is organized</secondary>
</indexterm>
<para>Because LDAP is intended to be a global directory service, data is organized
hierarchically, starting at a root and branching down into individual entries.</para>
<para>At the top level of the hierarchy, entries represent larger organizations.
Under larger organizations in the hierarchy, you might find entries for smaller
organizations. The hierarchy might end with entries for individual people,
or resources, as shown in the following figure.</para>
<figure id="hierarchy-in-ldap"><title>Hierarchy of Entries in a Directory</title>
<mediaobject>
<imageobject><imagedata entityref="hierovrw"></imageobject>
<textobject><simpara>Simple directory information tree with two organizational
unit entries and two user entries</simpara></textobject>
</mediaobject>
</figure>
<para><indexterm>
<primary>relative distinguished names (RDNs)</primary>
<secondary>definition of</secondary>
</indexterm><indexterm>
<primary>RDNs</primary>
<see>relative distinguished names (RDNs)</see></indexterm><indexterm>
<primary>distinguished names (DNs)</primary>
<secondary>definition of </secondary>
</indexterm><indexterm>
<primary>CNs</primary>
<see>common names (CNs)</see></indexterm><indexterm>
<primary>DNs</primary>
<see>distinguished names (DNs)</see></indexterm><indexterm>
<primary>common names (CNs)</primary>
</indexterm>Each entry is uniquely identified by a <firstterm>distinguished
name</firstterm> (DN). A DN includes a relative distinguished name (RDN),
that uniquely identifies the entry at that hierarchical level. For example, <literal>
bjensen</literal> and <literal>kjensen</literal> are different user IDs that
identify different entries at the same level. Following the RDN is a path
of names that trace the entry back to the root of the tree, such as <literal>ou=People,dc=example,dc=com
</literal>. <literal>DC</literal> is short for domain component. The full
DN for this example would be <literal>uid=bjensen,ou=People,dc=example,dc=com</literal>.
Here, <literal>uid</literal> is the user ID of the entry. <literal>ou</literal> is
short for organizational unit.</para>
<para><indexterm>
<primary>LDAP servers</primary>
<secondary>how data is distributed</secondary>
</indexterm>The data stored in a directory can be distributed among several
LDAP servers. For example, one LDAP server at <literal>Example.com</literal> might
contain entries representing North American organizational units and employees,
while another LDAP server might contain entries representing European organizational
units and employees.</para>
<para><indexterm>
<primary>LDAP servers</primary>
<secondary>how referrals work</secondary>
</indexterm><indexterm>
<primary>referrals</primary>
</indexterm>Some LDAP servers are set up to refer requests to other LDAP servers.
For example, if the LDAP server at <literal>Example.com</literal> receives
a request for information about an employee in a Pacific Rim branch, that
server can refer the request to the LDAP server at the Pacific Rim branch.
In this way, LDAP servers can appear to be a single source of directory information.
Even if an LDAP server does not contain the information you request, the server
can refer you to another server that does contain the information.</para>
</sect1>
<sect1 id="how-ldap-clients-servers-work"><title>How LDAP Clients and Servers
Work</title>
<indexterm>
<primary>LDAP servers</primary>
<secondary>LDAP clients and</secondary>
</indexterm><indexterm>
<primary>LDAP clients</primary>
<secondary>LDAP servers and</secondary>
</indexterm><indexterm>
<primary>LDAP clients</primary>
<secondary>operations performed by</secondary>
</indexterm>
<para>In the LDAP client-server model, LDAP servers such as &cnDirectoryServer;
make information about people, organizations, and resources accessible to
LDAP clients. LDAP defines operations that clients use to search and update
the directory.</para>
<itemizedlist>
<para>An LDAP client can perform these operations, among others:</para>
<listitem><para>Search for and retrieve entries from the directory</para>
</listitem>
<listitem><para>Add new entries to the directory</para></listitem>
<listitem><para>Update entries in the directory</para></listitem>
<listitem><para>Delete entries from the directory</para></listitem>
<listitem><para>Rename entries in the directory</para></listitem>
</itemizedlist>
<para>For example, to update an entry, an LDAP client submits the distinguished
name of the entry with updated attribute information to the LDAP server. The
LDAP server uses the distinguished name to find the entry. The server then
performs a modify operation to update the entry in the directory.</para>
<para><indexterm>
<primary>LDAP servers</primary>
<secondary>connecting with LDAP clients</secondary>
</indexterm><indexterm>
<primary>LDAP clients</primary>
<secondary>connecting with LDAP servers</secondary>
</indexterm>To perform any of these LDAP operations, an LDAP client needs
to establish a connection with an LDAP server. The LDAP protocol specifies
the use of TCP/IP port number 389, although servers can run on other ports.</para>
<para><indexterm>
<primary>LDAP servers</primary>
<secondary>authentication</secondary>
</indexterm><indexterm>
<primary>LDAP clients</primary>
<secondary>authentication</secondary>
</indexterm>The LDAP protocol also defines a simple method for authentication.
LDAP servers can be set up to restrict permissions to the directory. Before
an LDAP client can perform an operation on an LDAP server, the client must
authenticate to the server. Clients typically authenticate by supplying a
distinguished name and password. If the user identified by the distinguished
name does not have permission to perform the operation, the server does not
execute the operation.</para></sect1>
<sect1 id="understanding-ldapv3"><title>Understanding LDAP v3</title>
<indexterm>
<primary>LDAP</primary>
<secondary>version 3</secondary>
</indexterm>
<para><ulink url="http://www.ietf.org/rfc/rfc4511.txt" type="text_url">RFC
4511</ulink> specifies LDAP version 3. Use this version of the protocol when
writing new client applications.</para>
<para>Many LDAP servers continue to support LDAP version 2 for use with legacy
clients. This version of the protocol is specified in <ulink
url="http://www.ietf.org/rfc/rfc1777.txt" type="text_url">RFC 1777</ulink>.</para>
<itemizedlist>
<para>LDAP v3 includes new features not present in version 2:</para>
<listitem><para>Clients and servers can specify <firstterm>controls</firstterm> that
extend the functionality of an LDAP operation.</para></listitem>
<listitem><para>Clients can request that the server perform <firstterm>extended
operations</firstterm>, operations not included in the list of standard LDAP
operations.</para></listitem>
<listitem><para>Clients can use <firstterm>Simple Authentication and Security
Layer</firstterm> (SASL) mechanisms to authenticate to the directory. SASL
is specified in <ulink url="http://www.ietf.org/rfc/rfc4422.txt" type="text_url">
RFC 4422</ulink>.</para></listitem><?Pub Caret>
<listitem><para>Servers, known as <firstterm>Directory System Agents</firstterm> (DSAs),
have <firstterm>DSA-specific entries</firstterm> (DSEs). DSEs provide information
about the versions of the LDAP protocol that the server supports. DSEs also
provide a list of the controls, extended operations, and SASL mechanisms supported
by the server. Finally, DSEs specify the naming contexts of the server. Naming
contexts are portions of the directory information tree managed by the server.</para>
</listitem>
<listitem><para>Servers make their <firstterm>schemas</firstterm>, which define
the object classes, attributes, syntaxes, and matching rules enforced by the
directory, available to clients through the root DSE.</para></listitem>
<listitem><para><indexterm>
<primary>UTF-8</primary>
<secondary>support of</secondary>
</indexterm>Both client and server applications can support data in UTF-8. <firstterm>
UTF-8</firstterm> is a transformation format of the Universal Character Set
standard. UTF-8 is specified in <ulink url="http://www.ietf.org/rfc/rfc3269.txt"
type="text_url">RFC 3269</ulink>. With UTF-8, clients can request and receive
data that is tagged with language information.</para></listitem>
</itemizedlist>
</sect1>
</chapter>