Mozilla/mozilla/directory/docs/ldapcsdk/csdk-controls.sgm
richm%stanfordalumni.org dd758b072f initial import of docbook contribution from Sun
git-svn-id: svn://10.0.0.236/trunk@228382 18797224-902f-48f8-a5cc-f745e15eee43
2007-06-20 14:26:52 +00:00

2029 lines
82 KiB
Plaintext

<!--
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-controls"><title>LDAP Controls With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>LDAP controls</secondary>
</indexterm><highlights>
<para>This chapter explains how LDAP controls work and how to use them.</para>
<itemizedlist>
<para>This chapter covers the following topics:</para>
<listitem><para><olink targetptr="bdaim">How LDAP Controls Work With Directory
SDK for C</olink></para></listitem>
<listitem><para><olink targetptr="bdain">Using Controls in the LDAP API</olink></para>
</listitem>
<listitem><para><olink targetptr="bdaio">Determining the Controls Supported
by the Server With Directory SDK for C</olink></para></listitem>
<listitem><para><olink targetptr="bdaip">Using the Server-Side Sorting Control
With Directory SDK for C</olink></para></listitem>
<listitem><para><olink targetptr="bdaiv">Using the Persistent Search Control
With Directory SDK for C</olink></para></listitem>
<listitem><para><olink targetptr="bdaiw">Using the Entry Change Notification
Control With Directory SDK for C</olink></para></listitem>
<listitem><para><olink targetptr="bdaix">Using the Virtual List View Control
With Directory SDK for C</olink></para></listitem>
<listitem><para><olink targetptr="bdaiy">Using the Manage DSA IT Control With
Directory SDK for C</olink></para></listitem>
<listitem><para><olink targetptr="bdaiz">Using Password Policy Controls With
Directory SDK for C</olink></para></listitem>
<listitem><para><olink targetptr="bdaja">Using the Proxied Authorization Control
With Directory SDK for C</olink></para></listitem>
<listitem><para><olink targetptr="controls-authzid">Using the Authorization
Identity Bind Request Control With Directory SDK for C</olink></para></listitem>
<listitem><para><olink targetptr="controls-get-effective-rights">Using the
Get Effective Rights Request Control With Directory SDK for C</olink></para>
</listitem>
<listitem><para><olink targetptr="controls-real-attrs-only">Using the Real
Attributes Only Request Control With Directory SDK for C</olink></para>
</listitem>
<listitem><para><olink targetptr="controls-virtual-attrs-only">Using the Virtual
Attributes Only Request Control With Directory SDK for C</olink></para>
</listitem>
</itemizedlist>
</highlights>
<sect1 id="bdaim"><title>How LDAP Controls Work With Directory SDK for C</title>
<para>LDAP v3, as documented in <ulink url="http://www.ietf.org/rfc/rfc4511.txt"
type="text_url">RFC 4511</ulink>, allows clients and servers to use controls
as a mechanism for extending an LDAP operation. A <firstterm>control</firstterm> is
a way to specify additional information as part of a request and a response.
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, &cnDirectoryServer; can
send a control back to a client to indicate that the client password has expired,
or that the password is going to expire.</para>
<itemizedlist>
<para>A control specifies the following information:</para>
<listitem><para>A unique object identifier (OID) as defined by the creator
of the control</para><para>The OID identifies the control. <olink targetptr="controls-oids">Table 16&ndash;1</olink> names common OIDs.</para>
</listitem>
<listitem><para>An indication of whether or not the control is critical to
the operation</para></listitem>
<listitem><para>Optional data related to the control</para><para>For example,
the server-side sort control needs the attributes that would be used for sorting
search results.</para></listitem>
</itemizedlist>
<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 the control, and if the control is
appropriate, the server should make use of the control when performing the
operation.</para></listitem>
<listitem>
<itemizedlist>
<para>If the server does not support the control type, and 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 return
the result code <errorcode>LDAP_UNAVAILABLE_CRITICAL_EXTENSION</errorcode>.</para>
</listitem>
<listitem><para>If the control is not marked as critical to the operation,
the server should ignore the control and perform the operation.</para>
</listitem>
</itemizedlist>
</listitem>
</itemizedlist>
<para>If you plan to use a control, make sure that the server supports the
control. See <olink targetptr="bdaio">Determining the Controls Supported by
the Server With Directory SDK for C</olink> for details.</para></sect1>
<sect1 id="bdain"><title>Using Controls in the LDAP API</title>
<itemizedlist>
<para>&DirectorySDKForC; supports two types of controls:</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 SDK only and are
never sent to the server.</para></listitem>
</itemizedlist>
<para>In the SDK, a control is represented by an <structname>LDAPControl</structname> structure.
</para>
<itemizedlist>
<para>The fields in this structure represent the data in a control.</para>
<listitem><para><literal>ldctl_oid</literal> specifies the OID of the control.</para>
</listitem>
<listitem><para><literal>ldctl_value</literal> contains a <literal>berval</literal> structure
that contains data that is associated with the control.</para></listitem>
<listitem><para><literal>ldctl_iscritical</literal> specifies whether or not
the control is critical to the operation. <literal>LDAP_OPT_ON</literal> indicates
that the control is critical. <literal>LDAP_OPT_OFF</literal> indicates that
the control is not critical.</para></listitem>
</itemizedlist>
<para>The following shows the <structname>LDAPControl</structname> structure
definition.</para>
<example id="control-structure"><title><structname>LDAPControl</structname> Structure
</title>
<programlisting>typedef struct ldapcontrol {
char *ldctl_oid;
struct berval ldctl_value;
char ldctl_iscritical;
} LDAPControl;</programlisting>
</example>
<para>You can allocate space for the control, then create the control yourself.
You can also call a function to create the control. For example, you can call
the <function>ldap_create_sort_control</function> function to create a server-side
sorting control. To include a control in a request, call one of the LDAP v3
API functions, which are functions with names that end with <function>_ext</function> and <function>
_ext_s</function>. These functions allow you to pass in an array of server
controls and an array of client controls.</para>
<para>You can also include controls in a request by specifying the array of
controls in the <literal>LDAP_OPT_SERVER_CONTROLS</literal> option. However,
these controls are sent to the server with every request. If the control is
specific to a certain type of operation, you should use functions with names
that end with <function>_ext</function> and <function>_ext_s</function> instead.</para>
<para>To retrieve any controls included in a server&rsquo;s response, call
the <function>ldap_parse_result</function> function. You can then retrieve
data from the returned controls yourself by checking the fields of the <structname>
LDAPControl</structname> structure or by calling additional functions such
as <function>ldap_parse_sort_control</function>.</para>
<para>After working with a control, or with an array of controls, free the
controls from memory. Call <function>ldap_control_free</function> or <function>ldap_controls_free
</function> function.</para></sect1>
<sect1 id="bdaio"><title>Determining the Controls Supported by the Server
With &DirectorySDKForC;</title>
<para>According to LDAP v3, servers should list any controls that the server
supports in the <literal>supportedControl</literal> attribute in the root
DSE, which is described in <olink targetptr="csdk-server-info">Chapter&nbsp;14,
Getting Server Information With Directory SDK for C</olink>.</para>
<para>The following table shows OIDs for server controls that might be referenced
in the <literal>supportedControl</literal> attribute.</para>
<table frame="topbot" pgwide="1" id="controls-oids"><title>LDAP v3 Server
Controls for Directory SDK for C</title>
<tgroup cols="3"><colspec colnum="1" colwidth="25*"><colspec colnum="2"
colwidth="45*"><colspec colnum="3" colwidth="30*">
<thead>
<row>
<entry>
<para>OID</para></entry>
<entry>
<para>Name in <filename class="headerfile">ldap.h</filename></para></entry>
<entry>
<para>Instructions </para></entry>
</row>
</thead>
<tbody>
<row>
<entry>
<para><literal>1.2.840.113556.1.4.473</literal>, <literal>1.2.840.113556.1.4.474</literal></para>
</entry>
<entry>
<para><literal>LDAP_CONTROL_SORTREQUEST</literal>, <literal>LDAP_CONTROL_SORTRESPONSE
</literal></para></entry>
<entry>
<para><olink targetptr="bdaip">Using the Server-Side Sorting Control With
Directory SDK for C</olink></para></entry>
</row>
<row>
<entry>
<para><literal>1.3.6.1.4.1.42.2.27.8.5.1</literal></para></entry>
<entry>
<para><literal>LDAP_CONTROL_PASSWD_POLICY</literal></para></entry>
<entry>
<para><olink targetptr="bdaiz">Using Password Policy Controls With Directory
SDK for C</olink></para></entry>
</row>
<row>
<entry>
<para><literal>1.3.6.1.4.1.42.2.27.9.5.2</literal></para></entry>
<entry>
<para><literal>LDAP_CONTROL_GETEFFECTIVERIGHTS_REQUEST</literal></para></entry>
<entry>
<para><olink targetptr="controls-get-effective-rights">Using the Get Effective
Rights Request Control With Directory SDK for C</olink></para></entry>
</row>
<row>
<entry>
<para><literal>1.3.6.1.4.1.42.2.27.9.5.8</literal></para></entry>
<entry>
<para><literal>LDAP_CONTROL_ACCOUNT_USABLE</literal></para></entry>
<entry>
<para><olink targetptr="bdaiz">Using Password Policy Controls With Directory
SDK for C</olink></para></entry>
</row>
<row>
<entry>
<para><literal>2.16.840.1.113730.3.4.2</literal></para></entry>
<entry>
<para><literal>LDAP_CONTROL_MANAGEDSAIT</literal></para></entry>
<entry>
<para><olink targetptr="bdaiy">Using the Manage DSA IT Control With Directory
SDK for C</olink></para></entry>
</row>
<row>
<?PubTbl row rht="0.98in">
<entry>
<para><literal>2.16.840.1.113730.3.4.3</literal></para></entry>
<entry>
<para><literal>LDAP_CONTROL_PERSISTENTSEARCH</literal></para></entry>
<entry>
<para><olink targetptr="bdaiv">Using the Persistent Search Control With Directory
SDK for C</olink></para></entry>
</row>
<row>
<entry>
<para><literal>2.16.840.1.113730.3.4.7</literal></para></entry>
<entry>
<para><literal>LDAP_CONTROL_ENTRYCHANGE</literal></para></entry>
<entry>
<para><olink targetptr="bdaiw">Using the Entry Change Notification Control
With Directory SDK for C</olink></para></entry>
</row>
<row>
<entry>
<para><literal>2.16.840.1.113730.3.4.4</literal></para></entry>
<entry>
<para><literal>LDAP_CONTROL_PWEXPIRED</literal></para></entry>
<entry>
<para><olink targetptr="bdaiz">Using Password Policy Controls With Directory
SDK for C</olink></para></entry>
</row>
<row>
<entry>
<para><literal>2.16.840.1.113730.3.4.5</literal></para></entry>
<entry>
<para><literal>LDAP_CONTROL_PWEXPIRING</literal></para></entry>
<entry>
<para><olink targetptr="bdaiz">Using Password Policy Controls With Directory
SDK for C</olink></para></entry>
</row>
<row>
<entry>
<para><literal>2.16.840.1.113730.3.4.9</literal>, <literal>2.16.840.1.113730.3.4.10
</literal></para></entry>
<entry>
<para><literal>LDAP_CONTROL_VLVREQUEST</literal>, <literal><?SolBook prefpagebreak><?><?SolBook linebreak><?></literal></para>
<para><literal>LDAP_CONTROL_VLVRESPONSE</literal></para></entry>
<entry>
<para><olink targetptr="bdaix">Using the Virtual List View Control With Directory
SDK for C</olink></para></entry>
</row>
<row>
<entry>
<para><literal>2.16.840.1.113730.3.4.12</literal>, <literal>2.16.840.1.113730.3.4.18
</literal></para></entry>
<entry>
<para><literal>LDAP_CONTROL_PROXYAUTH</literal>, </para>
<para><literal>LDAP_CONTROL_PROXIEDAUTH</literal></para></entry>
<entry>
<para><olink targetptr="bdaja">Using the Proxied Authorization Control With
Directory SDK for C</olink></para></entry>
</row>
<row>
<entry>
<para><literal>2.16.840.1.113730.3.4.15</literal>, <literal>2.16.840.1.113730.3.4.16
</literal></para></entry>
<entry>
<para><literal>LDAP_CONTROL_AUTHZID_RES</literal>, <literal>LDAP_CONTROL_AUTHZID_REQ
</literal></para>
<para>Also known as <literal>LDAP_CONTROL_AUTH_RESPONSE</literal>, <literal>LDAP_CONTROL_AUTH_REQUEST
</literal></para></entry>
<entry>
<para><olink targetptr="controls-authzid">Using the Authorization Identity
Bind Request Control With Directory SDK for C</olink></para></entry>
</row>
<row>
<entry>
<para><literal>2.16.840.1.113730.3.4.17</literal></para></entry>
<entry>
<para><literal>LDAP_CONTROL_REAL_ATTRS_ONLY</literal></para></entry>
<entry>
<para><olink targetptr="controls-real-attrs-only">Using the Real Attributes
Only Request Control With Directory SDK for C</olink></para></entry>
</row>
<row>
<entry>
<para><literal>2.16.840.1.113730.3.4.19</literal></para></entry>
<entry>
<para><literal>LDAP_CONTROL_VIRTUAL_ATTRS_ONLY</literal></para></entry>
<entry>
<para><olink targetptr="controls-virtual-attrs-only">Using the Virtual Attributes
Only Request Control With Directory SDK for C</olink></para></entry>
</row>
</tbody>
</tgroup>
</table>
<para>The following sample command-line program searches for the root DSE.
The program then prints the values of the <literal>supportedControl</literal> attribute.
</para>
<example id="controls-supported-search-example"><title>Searching for Supported
Controls</title>
<programlisting>#include "ldap.h"
static char *usage = "Usage: listctrl -h hostname -p portnumber\n";
/* Associate OIDs of known controls with descriptions. */
struct oid2desc {
char *oid;
char *desc;
};
static struct oid2desc oidmap[] = {
{LDAP_CONTROL_ACCOUNT_USABLE, "Account availability control"}
{LDAP_CONTROL_AUTH_REQUEST, "Authorization bind identity request"}
{LDAP_CONTROL_AUTH_RESPONSE, "Authorization bind identity response"}
{LDAP_CONTROL_ENTRYCHANGE, "Entry change notification control"}
{LDAP_CONTROL_GETEFFECTIVERIGHTS_REQUEST, "Get effective rights control"}
{LDAP_CONTROL_MANAGEDSAIT, "Manage DSA IT control"}
{LDAP_CONTROL_PASSWD_POLICY, "Password policy control"}
{LDAP_CONTROL_PERSISTENTSEARCH, "Persistent search control"}
{LDAP_CONTROL_PROXIEDAUTH, "Proxied authorization (version 2) control"}
{LDAP_CONTROL_PROXYAUTH, "Proxied authorization (version 1) control"}
{LDAP_CONTROL_PWEXPIRED, "Password expired control"}
{LDAP_CONTROL_PWEXPIRING, "Password expiring control"}
{LDAP_CONTROL_REAL_ATTRS_ONLY, "Real attributes only control"}
{LDAP_CONTROL_SORTREQUEST, "Server-side sort request control"}
{LDAP_CONTROL_SORTRESPONSE, "Server-side sort response control"}
{LDAP_CONTROL_VIRTUAL_ATTRS_ONLY, "Virtual attributes only control"}
{LDAP_CONTROL_VLVREQUEST, "Virtual list view request control"}
{LDAP_CONTROL_VLVRESPONSE, "Virtual list view response control"}
{NULL, NULL}
};
int
main( int argc, char **argv )
{
LDAP *ld;
LDAPMessage *result, *e;
char *hostname = NULL;
char **vals;
char *attrs[2];
int i, j, c, portnumber = LDAP_PORT, rc;
LDAPControl **serverctrls = NULL, **clntctrls = NULL;
/* Parse the command line arguments. */
while ( ( c = getopt( argc, argv, "h:p:" ) ) != -1 ) {
switch ( c ) {
case 'h':
hostname = strdup( optarg );
break;
case 'p':
portnumber = atoi( optarg );
break;
default:
printf( "Unsupported option: %c\n", c );
printf( usage );
exit( 1 );
}
}
/* By default, connect to localhost at port 389. */
if ( hostname == NULL || hostname[0] == NULL ) {
hostname = "localhost";
}
/* Initialize the connection. Use prldap_init() for IPv6. */
if ( (ld = ldap_init( hostname, portnumber )) == 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 retrieve only the
supportedControl attribute. */
attrs[ 0 ] = "supportedControl";
attrs[ 1 ] = NULL;
rc = ldap_search_ext_s( ld, "", LDAP_SCOPE_BASE, "(objectclass=*)",
attrs, 0, serverctrls, clntctrls, NULL, NULL, &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 %s:%d returned result code %d (%s).\n"
"This server does not support the LDAPv3 protocol.\n",
hostname, portnumber, rc, ldap_err2string( rc ) );
return( 1 );
break;
/* If any other value is returned, an error must have occurred. */
default:
ldap_perror( ld, "ldap_search_ext_s" );
return( 1 );
break;
}
/* Get the root DSE from the results.
Since there is only one root DSE, there
should be only one entry in the results. */
e = ldap_first_entry( ld, result );
/* Get and print the values of the supportedControl attribute. */
if (e != NULL &amp;&amp;
(vals = ldap_get_values(ld, e, "supportedControl")) != NULL ) {
printf( "\nControls Supported by %s:%d\n", hostname, portnumber );
printf( "==================================================\n" );
for ( i = 0; vals[i] != NULL; i++ ) {
printf( "%s\n", vals[i] );
for ( j = 0; oidmap[j].oid != NULL; j++ ) {
if ( !strcmp( vals[i], oidmap[j].oid )) {
printf( "\t%s\n", oidmap[j].desc );
}
}
}
/* Free the values allocated by ldap_get_values(). */
ldap_value_free( vals );
printf( "\n" );
}
/* Free memory allocated by ldap_search_ext_s(). */
ldap_msgfree( result );
ldap_unbind( ld );
return( 0 );
}</programlisting>
</example>
</sect1>
<sect1 id="bdaip"><title>Using the Server-Side Sorting Control With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>LDAP controls</secondary>
<tertiary>server-side sorting</tertiary>
</indexterm>
<para>The control with OID <literal>1.2.840.113556.1.4.473</literal>, or <literal>
LDAP_CONTROL_SORTREQUEST</literal> as defined in the <literal>ldap.h</literal> header
file, is a server-side sorting control. When you send a search request with
this control to the server, the server should sort the results before sending
the results back to you.</para>
<para>The server-side sorting control is described in <ulink
url="http://www.ietf.org/rfc/rfc2891.txt" type="text_url">RFC 2891</ulink>.</para>
<sect2 id="bdaiq"><title>Specifying the Sort Order With &DirectorySDKForC;</title>
<para>To specify the sort order of the results, call the <function>ldap_create_sort_keylist
</function> function to create a sort key list from a string in the following
format:</para>
<programlisting>[-]<replaceable>attr-name</replaceable>[:<replaceable>matching-rule-oid
</replaceable>] &hellip;</programlisting>
<itemizedlist>
<listitem><para><replaceable>attr-name</replaceable> is the name of the attribute
to sort by.</para><para>You can specify a space-delimited list of attribute
names.</para></listitem>
<listitem><para><replaceable>matching-rule-oid</replaceable> is the optional
OID of a matching rule that you want to use for sorting.</para>
<programlisting>sn -givenname</programlisting>
</listitem>
<listitem><para>The minus sign indicates that the results should be sorted
in reverse order for that attribute. For example, the following string specifies
that results should be sorted by last name, <literal>sn</literal>, first in
ascending order. If multiple entries have the same last name, these entries
are sorted by first name, <literal>givenname</literal>, in descending order:</para>
</listitem>
</itemizedlist>
<para>Pass this string to <function>ldap_create_sort_keylist</function> to
create a sort key list, which is an array of <structname>LDAPsortkey</structname> structures.
You can use this technique to create the server-side sorting control.</para>
</sect2>
<sect2 id="bdair"><title>Creating the Server-Side Sorting Control With &DirectorySDKForC;</title>
<para>Next, to create the server-side sorting control, you pass the sort key
list, the array of <structname>LDAPsortkey</structname> structures, to the <function>
ldap_create_sort_control</function> function. The function passes back a newly
created sort control, an <structname>LDAPControl</structname>structure that
you can include in a search request.</para>
<para>You can specify whether or not the control is critical to the search
operation. If the control is marked as critical, but the server cannot sort
the results, the server should not send back any entries. See <olink targetptr="bdait">Interpreting the Results of Sorting With Directory SDK for
C</olink> for more information about the ramifications of marking the control
as critical.</para>
<para>After you call the <function>ldap_create_sort_control</function> function
and create the control, free the array of <structname>LDAPsortkey</structname> structures
by calling <function>ldap_free_sort_keylist</function>. When you are done
receiving sorted results from the server, free the <structname>LDAPControl</structname> structure
by calling <function>ldap_control_free</function>.</para></sect2>
<sect2 id="bdais"><title>Performing a Search With &DirectorySDKForC;</title>
<para>For the server to sort the results, add the newly created server-side
sorting control to a <literal>NULL</literal> terminated array of <structname>LDAPControl
</structname> structures. Pass this array to the <function>ldap_search_ext</function> function
or the <function>ldap_search_ext_s</function> function. The server returns
a result for the search operation. The server also returns a response control.
The <emphasis>response control</emphasis> indicates the success or failure
of the sort. To determine if sort was successful, use the following procedure.</para>
<task><title>To Search With a Sort Request for Directory SDK for C</title>
<procedure>
<step><para>Call <function>ldap_parse_result</function> to parse the result
of the search operation. </para><para>The function retrieves any response
controls sent back from the server.</para><para>Response controls are passed
back in a <literal>NULL</literal> terminated array of <structname>LDAPControl</structname> structures.
</para></step>
<step><para>Pass this array of structures as an argument to <function>ldap_parse_sort_control
</function> to retrieve the LDAP result code for the sorting operation.</para>
<para>If the sorting operation fails, the server can also return the name
of the attribute that caused the failure. The <function>ldap_parse_sort_control</function> function
also retrieves this name, if available.</para></step>
<step><para>Free the array by calling the <function>ldap_controls_free</function> function
when you are done parsing the array of response controls.</para><para>The
server can return the following result codes.</para>
<variablelist>
<varlistentry><term><errorcode>LDAP_SUCCESS</errorcode></term>
<listitem><para>The results were sorted successfully.</para>
</listitem>
</varlistentry>
<varlistentry><term><errorcode>LDAP_OPERATION_ERROR</errorcode></term>
<listitem><para>An internal server error occurred.</para>
</listitem>
</varlistentry>
<varlistentry><term><errorcode>LDAP_TIMELIMIT_EXCEEDED</errorcode></term>
<listitem><para>The maximum time allowed for a search was exceeded before
the server finished sorting the results.</para>
</listitem>
</varlistentry>
<varlistentry><term><errorcode>LDAP_STRONG_AUTH_REQUIRED</errorcode></term>
<listitem><para>The server refused to send back the sorted search results
because the server requires you to use a stronger authentication method.</para>
</listitem>
</varlistentry>
<varlistentry><term><errorcode>LDAP_ADMINLIMIT_EXCEEDED</errorcode></term>
<listitem><para>The server retrieved too many entries to sort.</para>
</listitem>
</varlistentry>
<varlistentry><term><errorcode>LDAP_NO_SUCH_ATTRIBUTE</errorcode></term>
<listitem><para>The sort key list specifies an attribute that does not exist.</para>
</listitem>
</varlistentry>
<varlistentry><term><errorcode>LDAP_INAPPROPRIATE_MATCHING</errorcode></term>
<listitem><para>The sort key list specifies a matching rule that is not recognized
or appropriate.</para>
</listitem>
</varlistentry>
<varlistentry><term><errorcode>LDAP_INSUFFICIENT_ACCESS</errorcode></term>
<listitem><para>The server did not send the sorted results because the client
has insufficient access rights.</para>
</listitem>
</varlistentry>
<varlistentry><term><errorcode>LDAP_BUSY</errorcode></term>
<listitem><para>The server is too busy to sort the results.</para>
</listitem>
</varlistentry>
<varlistentry><term><errorcode>LDAP_UNWILLING_TO_PERFORM</errorcode></term>
<listitem><para>The server is unable to sort the results.</para>
</listitem>
</varlistentry>
<varlistentry><term><errorcode>LDAP_OTHER</errorcode></term>
<listitem><para>This general result code indicates that the server failed
to sort the results for a reason other than the ones listed previously.</para>
</listitem>
</varlistentry>
</variablelist>
</step>
</procedure>
</task>
</sect2>
<sect2 id="bdait"><title>Interpreting the Results of Sorting With &DirectorySDKForC;</title>
<para>The following table shows the kinds of results to expect from the LDAP
server under different situations.</para>
<table frame="topbot" pgwide="1" id="controls-sort-results-list"><title>Server
Responses to Sorting Controls</title>
<tgroup cols="4"><colspec colnum="1" colwidth="20*"><colspec colnum="2"
colwidth="20*"><colspec colnum="3" colwidth="20*"><colspec colnum="4"
colwidth="40*">
<thead>
<row rowsep="1">
<entry colsep="0">
<para>Does the server support the sort control?</para></entry>
<entry colsep="0">
<para>Is the sort control marked as critical?</para></entry>
<entry colsep="0">
<para>Other Conditions</para></entry>
<entry colsep="0">
<para>Results From LDAP Server</para></entry>
</row>
</thead>
<tbody>
<row rowsep="0">
<entry colsep="0">
<para>Server does not support the 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"></entry>
<entry colsep="0">
<para>Control is not marked as critical.</para></entry>
<entry colsep="0"></entry>
<entry colsep="0">
<para>The server ignores the sorting control. Instead, the server returns
the entries unsorted.</para></entry>
</row>
<row>
<entry colsep="0">
<para>Server does support the 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 by using the specified sort key list.</para>
</entry>
<entry colsep="0">
<para>The server does not send back any entries. 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>
</entry>
</row>
<row>
<entry colsep="0"></entry>
<entry colsep="0">
<para>Control is not marked as critical.</para></entry>
<entry colsep="0"></entry>
<entry colsep="0">
<para>The server returns the entries unsorted. 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></entry>
</row>
<row>
<entry colsep="0"></entry>
<entry colsep="0">
<para>Not applicable, might or might not be marked as critical.</para></entry>
<entry colsep="0">
<para>The server successfully sorted the entries.</para></entry>
<entry colsep="0">
<para>The server sends back the sorted entries. The server sends back the
sorting response control. The response control specifies the result code of
the sort attempt, <errorcode>LDAP_SUCCESS</errorcode>.</para></entry>
</row>
<row>
<entry colsep="0"></entry>
<entry colsep="0"></entry>
<entry colsep="0">
<para>The search failed for any reason.</para></entry>
<entry colsep="0">
<para>The server sends back a result code for the search operation. The server
does not send back the sorting response control.</para></entry>
</row>
</tbody>
</tgroup>
</table>
</sect2>
<sect2 id="bdaiu"><title>Server-Side Sorting Control Sample Program for Directory
SDK for C</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>
<example id="csdk-controls-sort-example"><title>Applying Server&mdash;Side
Sorting Control for Direcory SDK for C</title>
<programlisting>#include &lt;stdio.h>
#include "ldap.h"
/* Change these as needed. */
#define HOSTNAME "localhost"
#define PORTNUMBER 389
int
main( int argc, char **argv )
{
LDAP *ld;
LDAPMessage *result, *e;
char *attrfail, *matched = NULL, *errmsg = NULL;
char **vals, **referrals;
int rc, parse_rc, version;
unsigned long rcode;
LDAPControl *sortctrl = NULL;
LDAPControl *requestctrls[ 2 ];
LDAPControl **resultctrls = NULL;
LDAPsortkey **sortkeylist;
/* Get a handle to an LDAP connection. Use prldap_init() for IPv6. */
if ( (ld = ldap_init( HOSTNAME, PORTNUMBER ) ) == NULL ) {
perror( "ldap_init" );
return( 1 );
}
version = LDAP_VERSION3;
ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &amp;version );
/* Create a sort key list that specifies the sort order of the results.
Sort the results by last name first, then by first name. */
ldap_create_sort_keylist( &amp;sortkeylist, "sn -givenname" );
/* Create the sort control. */
rc = ldap_create_sort_control( ld, sortkeylist, 1, &amp;sortctrl );
if ( rc != LDAP_SUCCESS ) {
fprintf( stderr,
"ldap_create_sort_control: %s\n",
ldap_err2string( rc ) );
ldap_unbind( ld );
return( 1 );
}
requestctrls[ 0 ] = sortctrl;
requestctrls[ 1 ] = NULL;
/* Search for all entries in Sunnyvale */
rc = ldap_search_ext_s( ld, "dc=example,dc=com", LDAP_SCOPE_SUBTREE,
"(mail=*example.com*)", NULL, 0, requestctrls,
NULL, NULL, 0, &amp;result );
if ( rc != LDAP_SUCCESS ) {
fprintf( stderr, "ldap_search_ext_s: %s\n", ldap_err2string( rc ) );
ldap_unbind( ld );
return( 1 );
}
parse_rc = ldap_parse_result( ld, result, &amp;rc, &amp;matched,
&amp;errmsg, &amp;referrals, &amp;resultctrls, 0 );
if ( parse_rc != LDAP_SUCCESS ) {
fprintf( stderr,
"ldap_parse_result: %s\n",
ldap_err2string( parse_rc ) );
ldap_unbind( ld );
return( 1 );
}
if ( rc != LDAP_SUCCESS ) {
fprintf( stderr, "ldap_search_ext_s: %s\n", ldap_err2string( rc ) );
if ( errmsg != NULL &amp;&amp; *errmsg != '\0' ) {
fprintf( stderr, "%s\n", errmsg );
}
ldap_unbind( ld );
return( 1 );
}
parse_rc =
ldap_parse_sort_control( ld, resultctrls, &amp;rcode, &amp;attrfail );
if ( parse_rc != LDAP_SUCCESS ) {
fprintf( stderr,
"ldap_parse_sort_control: %s\n",
ldap_err2string( parse_rc ) );
ldap_unbind( ld );
return( 1 );
}
if ( rcode != LDAP_SUCCESS ) {
fprintf( stderr, "Sort error: %s\n", ldap_err2string( rcode ) );
if ( attrfail != NULL &amp;&amp; *attrfail != '\0' ) {
fprintf( stderr, "Bad attribute: %s\n", attrfail );
}
ldap_unbind( ld );
return( 1 );
}
/* for each entry print out name + all attrs and values */
for ( e = ldap_first_entry( ld, result ); e != NULL;
e = ldap_next_entry( ld, e ) ) {
if ((vals = ldap_get_values( ld, e, "sn")) != NULL ) {
if ( vals[0] != NULL ) {
printf( "%s", vals[0] );
}
ldap_value_free( vals );
}
if ((vals = ldap_get_values( ld, e, "givenname")) != NULL ) {
if ( vals[0] != NULL ) {
printf( "\t%s", vals[0] );
}
ldap_value_free( vals );
}
printf( "\n" );
}
ldap_msgfree( result );
ldap_free_sort_keylist( sortkeylist );
ldap_control_free( sortctrl );
ldap_controls_free( resultctrls );
ldap_unbind( ld );
return( 0 );
}</programlisting>
</example>
</sect2>
</sect1>
<sect1 id="bdaiv"><title>Using the Persistent Search Control With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>LDAP controls</secondary>
<tertiary>persistent search</tertiary>
</indexterm>
<para>The control OID <literal>2.16.840.1.113730.3.4.3</literal>, <literal>LDAP_CONTROL_PERSISTENTSEARCH
</literal> as defined in the <literal>ldap.h</literal> header file, is the
persistent search control. A <firstterm>persistent search</firstterm> is an
ongoing search operation that allows your LDAP client to get notification
of changes to the directory.</para>
<para>The persistent search control is described in the Internet Draft <citetitle>
Persistent Search: A Simple LDAP Change Notification Mechanism</citetitle>.</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. When an entry in the directory
changes, 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 these conditions are true, the server sends
the entry to your client.</para>
<para>To create a persistent search control, call <function>ldap_create_persistentsearch_control
</function> as shown here.</para>
<example id="controls-psearch-prototype"><title><function>ldap_create_persistentsearch_control
</function> Prototype for Directory SDK for C</title>
<screen>int ldap_create_persistentsearch_control( LDAP *ld,
int changetypes, int changesonly, int return_echg_ctls,
char ctl_iscritical, LDAPControl **ctrlp );</screen>
</example>
<itemizedlist>
<para>You can specify the following information:</para>
<listitem><para><literal>changetypes</literal> specifies the type of change
you want to track.</para>
<itemizedlist>
<para>You can specify any of the following or any combination of the following
using a bitwise or operator, <literal>|</literal>.</para>
<listitem><para><literal>LDAP_CHANGETYPE_ADD</literal> indicates that you
want to track added entries.</para></listitem>
<listitem><para><literal>LDAP_CHANGETYPE_DELETE</literal> indicates that you
want to track deleted entries.</para></listitem>
<listitem><para><literal>LDAP_CHANGETYPE_MODIFY</literal> indicates that you
want to track modified entries.</para></listitem>
<listitem><para><literal>LDAP_CHANGETYPE_MODDN</literal> indicates that you
want to track renamed entries.</para></listitem>
<listitem><para><literal>LDAP_CHANGETYPE_ANY</literal> indicates that you
want to track all changes to entries.</para></listitem>
</itemizedlist>
</listitem>
<listitem><para><literal>changesonly</literal> indicates whether or not you
want the server to return all entries that initially matched the search criteria.
Use <literal>0</literal> to return all entries, or non zero to return only
the entries that change.</para></listitem>
<listitem><para><literal>return_echg_ctls</literal> indicates whether or not
you want entry change notification controls included with every modified entry
returned by the server. Use a non zero value to return entry change notification
controls.</para></listitem>
</itemizedlist>
<para>You can use this control in conjunction with an entry change notification
control. See <olink targetptr="bdaiw">Using the Entry Change Notification
Control With Directory SDK for C</olink> for details.</para>
<para>The <function>ldap_create_persistentsearch_control</function> function
passes back an <structname>LDAPControl</structname> structure that represents
the control in the <literal>ctrlp</literal> parameter. You can add the newly
created control to a <literal>NULL</literal> terminated array of <structname>LDAPControl
</structname> structures. Pass this array to the <function>ldap_search_ext</function> function.
</para>
<para>To end the persistent search, call the <function>ldap_abandon_ext</function> function.
Alternatively, call the <function>ldap_unbind</function> function to disconnect
from the server.</para>
<para>The example provided in <filename>examples/psearch.c</filename> shows
how to perform a persistent search.</para></sect1>
<sect1 id="bdaiw"><title>Using the Entry Change Notification Control With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>LDAP controls</secondary>
<tertiary>entry change notification</tertiary>
</indexterm>
<para>The control with OID <literal>2.16.840.1.113730.3.4.7</literal>, <literal>LDAP_CONTROL_ENTRYCHANGE
</literal> as defined in the <literal>ldap.h</literal> header file, is the
entry change notification control. This control contains additional information
about the change to the entry. The information includes the type of change,
and the change number, which corresponds to an item in the server&rsquo;s
change log. If the entry was renamed, the control also contains the old DN
of the entry in the change log.</para>
<para>You use this control in conjunction with a persistent search control.
You can specify the preference for returning entry change notification controls.
The server then includes an entry change notification control with each entry
found by the search. To retrieve and parse an entry change notification control
included with an entry, follow this procedure.</para>
<task><title>To Use Entry Change Notification With Directory SDK for C</title>
<procedure>
<step><para>Pass the <structname>LDAPMessage</structname> structure that represents
an entry to the <function>ldap_get_entry_controls</function> function.</para>
</step>
<step><para>Pass the entry change notification control to the <function>ldap_parse_entrychange_control
</function> function.</para><para>For more information, see <olink targetptr="bdaiv">Using the Persistent Search Control With Directory SDK for
C</olink>.</para></step>
</procedure>
</task>
</sect1>
<sect1 id="bdaix"><title>Using the Virtual List View Control With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>LDAP controls</secondary>
<tertiary>virtual list view</tertiary>
</indexterm>
<para>The control with OID <literal>2.16.840.1.113730.3.4.9</literal>, <literal>LDAP_CONTROL_VLVREQUEST
</literal> as defined in the <literal>ldap.h</literal> header file, is a virtual
list view control. When you send a search request with this control and a
server-side sorting control, the server should sort the results. The server
should then return the specified subset of entries back to your client.</para>
<para>The virtual list view control is described in the Internet Draft, <citetitle>
LDAP Extensions for Scrolling View Browsing of Search Results</citetitle>.</para>
</sect1>
<sect1 id="bdaiy"><title>Using the Manage DSA IT Control With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>LDAP controls</secondary>
<tertiary>manage DSA IT</tertiary>
</indexterm>
<para>The control with OID <literal>2.16.840.1.113730.3.4.2</literal>, <literal>LDAP_CONTROL_MANAGEDSAIT
</literal> as defined in the <literal>ldap.h</literal> header file, is the
manage DSA IT control. You can use this control to manage search references
in the directory. To create this control, create an <structname>LDAPControl</structname> structure
and set the <literal>ldctl_oid</literal> field to <literal>2.16.840.1.113730.3.4.2
</literal>.</para>
<para>When you add this control to the array of <structname>LDAPControl</structname> structures
for <function>ldap_search_ext</function> or <function>ldap_modify_ext</function>,
the server treats search references as ordinary entries. 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>
<para>The manage DSA IT control is described in <ulink
url="http://www.ietf.org/rfc/rfc2891.txt" type="text_url">RFC 2891</ulink>.</para>
</sect1>
<sect1 id="bdaiz"><title>Using Password Policy Controls With &DirectorySDKForC;</title>
<para>&cnDirectoryServer; offers three password policy response controls sent
back to a client that performs a bind operation. The server also offers an
account availability control that does not require a bind to return status
about a client account.</para>
<sect2 id="exp-control"><title>Using Password Policy Expiration Controls With
Directory SDK for C</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 with OID <literal>2.16.840.1.113730.3.4.4</literal>, <literal>
LDAP_CONTROL_PWEXPIRED</literal>, is the expired password control.</para><para>This
control serves when the server requires users to change passwords when first
logging in, and after password reset. After the first login, and after password
reset, the server sends this control to indicate that the client needs to
change the password immediately. At this point, the only operation that the
client can perform is to change the user&rsquo;s password. If the client requests
any other operation, the server sends back an <errorcode>LDAP_UNWILLING_TO_PERFORM
</errorcode> result code with an expired password control.</para></listitem>
<listitem><para>The control with OID <literal>2.16.840.1.113730.3.4.5</literal>, <literal>
LDAP_CONTROL_PWEXPIRING</literal>, is the password expiration warning control.</para>
<para>This control is used if the server is configured to expire user passwords
after a certain amount of time. The server sends this control back to the
client if the client binds with a password that is to expire soon . The <structfield>
ldctl_value</structfield> field of the <structname>LDAPControl</structname> structure
specifies the number of seconds before the password expires.</para></listitem>
</itemizedlist>
<task><title>To Use Password Policy Expiration Controls With Directory SDK
for C</title>
<indexterm>
<primary>C SDK</primary>
<secondary>LDAP controls</secondary>
<tertiary>password policy</tertiary>
</indexterm>
<procedure>
<step><para>Call <function>ldap_simple_bind</function> to send a request for
an asynchronous bind operation.</para></step>
<step><para>Call <function>ldap_result</function> to get the results of the
operation.</para></step>
<step><para>Call <function>ldap_parse_result</function> to parse the result. </para>
<para>The function retrieves the server response controls from the result
as an array of <structname>LDAPControl</structname> structures.</para></step>
<step><para>Check the <structfield>ldctl_oid</structfield> field to determine
the OID of the control and the <structfield>ldctl_value</structfield> field
for any data that is included in the control.</para></step>
</procedure>
</task>
</sect2>
<sect2 id="acc-avail-control"><title>Using the Account Availability Control
With Directory SDK for C</title>
<para>&cnDirectoryServer; offers an account availability control that does
not require a bind to return status about a client account. The account availability
control is assigned OID <literal>1.3.6.1.4.1.42.2.27.9.5.8</literal>, <literal>LDAP_CONTROL_ACCOUNT_USABLE
</literal>. This control allows the client to read information about an account
without having to bind as the user having that account.</para>
<task id="controls-userstatus"><title>To Use the Account Availability Control
With Directory SDK for C</title>
<indexterm>
<primary>C SDK</primary>
<secondary>LDAP controls</secondary>
<tertiary>account status</tertiary>
</indexterm>
<procedure>
<step><para>Allocate an <structname>LDAPuserstatus</structname> structure
to hold the values for the account status.</para></step>
<step><para>Create an account status control with <function>ldap_create_userstatus_control
</function>.</para></step>
<step><para>Read the entry for which you want account status, passing in the
control as part of the search.</para></step>
<step><para>Get the controls on the entry that the search returns.</para></step>
<step><para>Pass the <structname>LDAPuserstatus</structname> structure to <function>
ldap_parse_userstatus_control</function> to fill the structure.</para></step>
<step><para>Read account status information from the <structname>LDAPuserstatus</structname> structure.
</para></step>
</procedure>
<example id="example-checking-account-status">
<title>Checking Account Status With Directory SDK for C</title>
<para>This example displays status for Barbara Jensen's account.</para>
<programlisting>/*
* Get account status using the account status control.
*/
#include "examples.h"
int
main( int argc, char **argv )
{
LDAPuserstatus *status;
int version;
LDAP *ld;
int rc;
LDAPControl *status_ctrl = NULL;
LDAPControl *requestctrls[ 2 ];
LDAPMessage *result;
char *matched = NULL;
char *errmsg = NULL;
char **referrals;
LDAPControl **resultctrls = NULL;
LDAPMessage *msg;
LDAPControl **ectrls = NULL;
/* Allocate the LDAPuserstatus structure. */
if ( !( status = (LDAPuserstatus*)malloc(sizeof(LDAPuserstatus)) ) ) {
perror("malloc");
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 );
}
/* Create an account status control. */
rc = ldap_create_userstatus_control( ld, 1, &amp;status_ctrl );
if ( rc != LDAP_SUCCESS ) {
fprintf( stderr, "ldap_create_userstatus_control: %s\n",
ldap_err2string( rc ) );
ldap_unbind( ld );
return( 1 );
}
requestctrls[ 0 ] = status_ctrl;
requestctrls[ 1 ] = NULL;
/* Authenticate to the directory as a user. */
if ( ldap_simple_bind_s( ld, USER_DN, USER_PW ) != LDAP_SUCCESS ) {
ldap_perror( ld, "ldap_simple_bind_s" );
return( 1 );
}
/* Read the account entry using the control. */
rc = ldap_search_ext_s( ld, ENTRYDN, LDAP_SCOPE_BASE,
"(objectclass=*)", NULL, 0, requestctrls, NULL, NULL, 0, &amp;result );
if ( rc != LDAP_SUCCESS ) {
fprintf( stderr, "ldap_search_ext_s: %s\n", ldap_err2string( rc ) );
ldap_unbind( ld );
return( 1 );
}
/* Show the account status. */
rc = ldap_parse_result( ld, result, &amp;rc, &amp;matched, &amp;errmsg,
&amp;referrals, &amp;resultctrls, 0 );
if ( rc != LDAP_SUCCESS ) {
fprintf( stderr, "ldap_parse_result: %s\n", ldap_err2string( rc ) );
ldap_unbind( ld );
return( 1 );
}
for ( msg = ldap_first_message( ld, result );
msg != NULL;
msg = ldap_next_message ( ld, msg) ) {
if ( ldap_msgtype( msg ) != LDAP_RES_SEARCH_ENTRY ) continue;
if ( ldap_get_entry_controls( ld, msg, &amp;ectrls ) != LDAP_SUCCESS ) {
ldap_perror ( ld, "ldap_get_entry_controls" );
} else {
rc = ldap_parse_userstatus_control( ld, ectrls, status );
if ( rc != LDAP_SUCCESS ) {
fprintf( stderr,
"ldap_parse_userstatus_control: %s\n",
ldap_err2string( rc ) );
} else {
printf( "DN: %s\n", ENTRYDN );
if ( LDAP_US_ACCOUNT_USABLE == status->us_available ) {
printf( " Account is usable:\tY\n" );
} else {
printf( " Account is usable:\tN\n" );
}
printf( " Password expires in:\t%ld s\n",
status->us_expire );
if ( LDAP_US_ACCOUNT_INACTIVE == status->us_inactive ) {
printf( " Account is locked:\tY\n" );
} else {
printf( " Account is locked:\tN\n" );
}
if ( LDAP_US_ACCOUNT_RESET == status->us_reset ) {
printf( " Password was reset:\tY\n" );
} else {
printf( " Password was reset:\tN\n" );
}
if ( LDAP_US_ACCOUNT_EXPIRED == status->us_expired ) {
printf( " Password has expired:\tY\n" );
} else {
printf( " Password has expired:\tN\n" );
}
printf( " Grace logins left:\t%d\n",
status->us_remaining );
printf( " Account unlocks in:\t%d s\n",
status->us_seconds );
}
}
}
ldap_msgfree( result );
ldap_control_free( status_ctrl );
ldap_controls_free( resultctrls );
ldap_unbind( ld );
return( 0 );
}</programlisting>
</example>
</task>
</sect2>
<sect2 id="pwd-pol-control"><title>Using the Password Policy Control With
Directory SDK for C</title>
<para>&cnDirectoryServer; offers a password policy control to retrieve information
about the password policy that applies to the account used to bind to the
server. The password policy control is assigned OID <literal>1.3.6.1.4.1.42.2.27.8.5.1
</literal>, <literal>LDAP_CONTROL_PASSWD_POLICY</literal>.</para>
<task id="controls-password-policy"><title>To Use the Password Policy Control
With Directory SDK for C</title>
<indexterm>
<primary>C SDK</primary>
<secondary>LDAP controls</secondary>
<tertiary>password policy</tertiary>
</indexterm>
<procedure>
<step><para>Allocate an <structname>LDAPpwdpolicy</structname> structure to
hold the values for the account status.</para></step>
<step><para>Create a password policy control with <function>ldap_create_pwdpolicy_control
</function>.</para></step>
<step><para>Bind sending the password policy control.</para></step>
<step><para>Perform a bind, a modify, an add, a compare, or an extended operation,
getting the result controls.</para></step>
<step><para>Pass the <structname>LDAPpwdpolicy</structname> structure to <function>
ldap_parse_pwdpolicy_control</function> to fill the structure.</para></step>
<step><para>Read password policy information from the <structname>LDAPpwdpolicy</structname> structure.
</para></step>
</procedure>
<example id="example-checking-password-policy">
<title>Checking Password Policy for Directory SDK for C</title>
<para>This example displays the password policy that governs Barbara Jensen's
account retrieved during the bind operation.</para>
<programlisting>/*
* Get password policy information using the password policy control.
*/
#include "examples.h"
int
main( int argc, char **argv )
{
LDAPpwdpolicy *policy;
int version;
LDAP *ld;
int rc;
LDAPControl *pwpctrl = NULL;
LDAPControl *requestctrls[ 2 ];
int msgid;
LDAPMessage *result;
int parse_rc;
char *matched = NULL;
char *errmsg = NULL;
char **referrals;
LDAPControl **resultctrls = NULL;
/* Allocate the LDAPpwdpolicy structure. */
if ( !( policy = (LDAPpwdpolicy*)malloc(sizeof(LDAPpwdpolicy) ) ) ) {
perror("malloc");
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 );
}
/* Create a password policy control. */
rc = ldap_create_pwdpolicy_control( ld, 1, &amp;pwpctrl);
if ( rc != LDAP_SUCCESS ) {
fprintf( stderr, "ldap_create_pwdpolicy_control: %s\n",
ldap_err2string( rc ) );
ldap_unbind( ld );
return( 1 );
}
requestctrls[ 0 ] = pwpctrl;
requestctrls[ 1 ] = NULL;
/* Use the password policy control for the bind. */
rc = ldap_set_option( ld, LDAP_OPT_SERVER_CONTROLS, &amp;pwpctrl );
if ( rc != LDAP_SUCCESS ) {
ldap_perror( ld, "ldap_set_option" );
return ( 1 );
}
/* Authenticate to the directory, checking for result controls. */
msgid = ldap_simple_bind( ld, ENTRYDN, ENTRYPW );
if ( msgid &lt; 0 ) {
fprintf( stderr, "ldap_simple_bind: %s\n", ldap_err2string( rc ) );
if ( errmsg != NULL &amp;&amp; errmsg != '\0' ) {
fprintf( stderr, "%s\n", errmsg );
}
ldap_unbind( ld );
return ( 1 );
}
rc = ldap_result( ld, msgid, LDAP_MSG_ALL, NULL, &amp;result );
if ( rc &lt; 0 ) {
rc = ldap_get_lderrno( ld, NULL, NULL );
fprintf( stderr, "ldap_result: %s\n", ldap_err2string( rc ) );
ldap_unbind( ld );
return ( 1 );
}
parse_rc = ldap_parse_result( ld, result, &amp;rc, &amp;matched, &amp;errmsg,
&amp;referrals, &amp;resultctrls, 0 );
if ( parse_rc != LDAP_SUCCESS ) {
fprintf( stderr, "ldap_parse_result: %s\n", ldap_err2string( rc ) );
ldap_unbind( ld );
return ( 1 );
}
if ( rc != LDAP_SUCCESS ) {
fprintf( stderr, "ldap_simple_bind: %s\n", ldap_err2string( rc ) );
if ( errmsg != NULL &amp;&amp; errmsg != '\0' ) {
fprintf( stderr, "%s\n", errmsg );
}
}
if ( resultctrls == NULL ) {
fprintf( stderr, "No pwp result control from server.\n" );
ldap_unbind( ld );
return ( 1 );
}
/* Show the password policy information. */
parse_rc = ldap_parse_pwdpolicy_control( ld, resultctrls, policy );
if ( parse_rc != LDAP_SUCCESS ) {
fprintf( stderr, "ldap_parse_pwdpolicy_control: %s\n",
ldap_err2string( rc ) );
ldap_unbind( ld );
return ( 1 );
}
printf( "DN: %s\n", ENTRYDN );
switch ( policy->pp_warning ) {
case LDAP_PP_WARNING_NONE:
printf( " No warnings\n" );
break;
case LDAP_PP_WARNING_EXP:
printf( " Password expires in: %d s\n", policy->pp_warning_info );
break;
case LDAP_PP_WARNING_GRACE:
printf( " Grace logins left: %d", policy->pp_warning_info );
break;
default: printf( " Unrecognized password policy warning\n" ); break;
}
switch ( policy->pp_error ) {
case LDAP_PP_ERROR_NONE:
printf( " No errors\n" );
break;
case LDAP_PP_ERROR_EXPIRED:
printf( " Password has expired, and must be reset.\n" );
break;
case LDAP_PP_ERROR_LOCKED:
printf( " Account is locked.\n" );
break;
case LDAP_PP_ERROR_MUSTCHANGE:
printf( " Password has been reset, and must be changed.\n" );
break;
case LDAP_PP_ERROR_NOTMOD:
printf( " This user may not change the password.\n" );
break;
case LDAP_PP_ERROR_OLDPASSWD:
printf( " Old password must be supplied for this operation.\n" );
break;
case LDAP_PP_ERROR_NOQUALITY:
printf( " Password does not pass quality check.\n" );
break;
case LDAP_PP_ERROR_TOOSHORT:
printf( " Password is too short.\n" );
break;
case LDAP_PP_ERROR_MINAGE:
printf( " Password is too new to be modified already.\n" );
break;
case LDAP_PP_ERROR_INHISTORY:
printf( " Password has already been used.\n" );
break;
default: printf( " Unrecognized password policy error\n" ); break;
}
ldap_msgfree( result );
ldap_control_free( pwpctrl );
ldap_controls_free( resultctrls );
ldap_unbind( ld );
return( 0 );
}</programlisting>
</example>
</task>
</sect2>
</sect1>
<sect1 id="bdaja"><title>Using the Proxied Authorization Control With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>LDAP controls</secondary>
<tertiary>proxied authorization control</tertiary>
</indexterm>
<para>Proxied authorization is an extension to LDAP v3 that allows a bound
client to assume the identity of another directory entity without rebinding.
The rebind allows the client to perform operations as if it were bound as
the proxied directory entity. All directory access, including read, write,
search, compare, delete, and add operations, is supported by proxied authorization.
For example, suppose a client is bound as <literal>uid=bjensen,ou=Engineering,dc=example,dc=com
</literal>. The user <literal>bjensen</literal> does not have the right to
search the <literal>ou=Marketing,dc=example,dc=com</literal> tree. However, <literal>
uid=lboyd,ou=Marketing,dc=example,dc=com</literal> does have rights to search
the Marketing tree, and <literal>lboyd</literal> grants proxy rights to <literal>
bjensen</literal>. In this case, <literal>bjensen</literal> can bind as herself,
assume the identity of <literal>lboyd</literal>, and then search the Marketing
tree.</para>
<para>This feature is intended as a performance and administrative benefit
for certain types of directory usage. Specifically, applications that allow
many clients to access directory data without rebinding as another directory
entity might use this feature.</para>
<sect2 id="bdajb"><title>Proxy Right for Directory SDK for C</title>
<para>Proxied authorization adds an additional access right: <emphasis>proxy</emphasis>.
If an entry grants the proxy right, then the entity to which that right is
granted can assume the identity of the granting entity. For example, to allow <literal>
uid=bjensen</literal> the right to proxy as <literal>uid=lboyd</literal>,
add the Proxy Right access control instruction (ACI) as shown in the following
example. This ACI allows <literal>bjensen</literal> to assume the identity
of <literal>lboyd</literal> for all directory operations. The ACI gives <literal>
bjensen</literal> permission to do to the directory whatever <literal>lboyd</literal> has
permission to do.</para>
<example id="controls-proxy-aci"><title>Proxy Right ACI</title>
<programlisting>aci: (target = "ldap:///uid=lboyd,ou=Marketing,dc=example,dc=com")
(targetattr=*)
(version 3.0; aci "grant bjensen the right to proxy as lboyd";
allow(proxy)
userdn="ldap:///uid=bjensen,ou=Engineering,dc=example,dc=com";)</programlisting>
</example>
</sect2>
<sect2 id="bdajc"><title>Proxy Authorization Control With Directory SDK for
C</title>
<para>To support proxy authorization, an extension to LDAP v3, the proxy authorization
control has been added to &DirectorySDKForC; in the form of the <function>ldap_create_proxyauth_control
</function> function. You use this function to create the control that allows
a bound entity to assume the identity of another directory entry.</para>
<para>Proxy authorization is an optional LDAP server feature. Proxy authorization
might not be supported on all LDAP servers. You should call the proxy authorization
control function only when interacting with LDAP servers that support this
LDAP v3 extension. You can check on the support of this control by looking
at the root DSE <literal>supportedControl</literal> attribute. For example,
the following command uses the <command>ldapsearch</command> utility to display
the root DSE:</para>
<screen>$ ldapsearch -h localhost -p 389 -b "" -s base "(objectclass=*)"</screen>
<para>For the control to work, the server to connect to must support the server
control for Proxy Authorization, OID <literal>2.16.840.1.113730.3.4.12</literal>.
This control is <literal>LDAP_CONTROL_PROXYAUTH</literal> as defined in the <literal>
ldap.h</literal> header file.</para></sect2>
<sect2 id="bdajd"><title>Proxy Authorization Sample Program for Directory
SDK for C</title>
<para>The following sample program creates an LDAP connection, sets the Proxy
Authorization control, binds to the directory, and then performs a search
operation using the Proxy Authorization control.</para>
<example id="controls-proxy-auth-example"><title>Program to use Proxy Authorization
Control With Directory SDK for C</title>
<programlisting>#include "ldap.h"
int version;
LDAP *ld;
LDAPControl *requestctrls[ 2 ];
LDAPControl *pactrl = NULL;
/* Customize the following host and bind information for your site. */
int port=389;
char *host="directory.example.com";
char *baseDN="dc=example,dc=com";
/* Proxied auth specific information.
proxyDN is the entity that will be proxied.
bindDN and bindpw is for the bind entity that will use the proxyDN. */
char *proxyDN = "uid=lboyd,ou=marketing,dc=example,dc=com";
char *bindDN = "uid=bjensen,ou=engineering,dc=example,dc=com";
char *bindpw = "password";
/* Do general LDAP init stuff */
/* Get a handle to an LDAP connection. Use prldap_init() for IPv6. */
if ( (ld = ldap_init( host, port ) ) == NULL ) {
printf("ldap_init did not return a conn handle.\n");
return;
}
/* set version to ldap version 3 */
version = LDAP_VERSION3;
ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &amp;version );
/* authenticate to the directory */
if ( ldap_simple_bind_s( ld, bindDN, bindpw ) != LDAP_SUCCESS ) {
printf("ldap_simple_bind_s failed");
return (-1);
}
/* create the Proxy Authorization control */
if ( ldap_create_proxyauth_control( ld, proxyDN, 1, &amp;pactrl ) ) {
printf("ldap_create_proxyauth_control failed.\n");
if ( ldap_unbind( ld ) != LDAP_SUCCESS ) {
printf("ldap_unbind failed\n");
}
return(-1);
}
requestctrls[ 0 ] = pactrl;
requestctrls[ 1 ] = NULL;
/* Perform the search using the control */
printf("Searching for %s with the proxy auth control.\n", proxyDN);
if ( ldap_search_ext_s( ld, proxyDN, LDAP_SCOPE_SUBTREE, "(objectclass=*)",
NULL, 0, requestctrls, NULL, NULL, LDAP_NO_LIMIT, &amp;results ) !=
LDAP_SUCCESS ) {
printf("ldap_search_ext failed.\n");
printf("Something is wrong with proxied auth.\n");
} else {
print_search_results(ld, results);
}</programlisting>
</example>
</sect2>
</sect1>
<sect1 id="controls-authzid"><title>Using the Authorization Identity Bind
Request Control With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>LDAP controls</secondary>
<tertiary>authorization identity</tertiary>
</indexterm>
<para>The control with OID <literal>2.16.840.1.113730.3.4.16</literal>, <literal>
LDAP_CONTROL_AUTHZID_REQ</literal>, is the authorization identity bind request
control. This control lets you request the authorization ID when binding to
the server.</para>
<task><title>To Retrieve the Authorization ID</title>
<tasksummary>
<para>&cnDirectoryServer; supports the authorization identity bind request
and response controls defined in <ulink url="http://www.ietf.org/rfc/rfc3829.txt"
type="text">RFC 3829</ulink>. The server also allows you to retrieve the authorization
identity value as a string.</para></tasksummary>
<procedure>
<step><para>Create an authorization identity request control using the <function>
ldap_create_authzid_control</function> function.</para></step>
<step><para>Bind sending the authorization identity request control.</para>
</step>
<step><para>Read the authorization identity from the response control using
the <function>ldap_parse_authzid_control</function> function.</para></step>
</procedure>
<example>
<title>Retrieving the Authorization ID</title>
<para>This example gets the authorization ID for Barbara Jensen</para>
<programlisting>/*
* Get the authorization ID for an operation.
*/
#include "examples.h"
int
main( int argc, char **argv )
{
int version;
LDAP *ld;
int rc;
LDAPControl *authzidctrl = NULL;
LDAPControl *requestctrls[ 2 ];
int msgid;
LDAPMessage *result;
int parse_rc;
char *matched = NULL;
char *errmsg = NULL;
char **referrals;
LDAPControl **resultctrls = NULL;
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 );
}
/* Create a authorization ID control. */
rc = ldap_create_authzid_control( ld, 1, &amp;authzidctrl );
if ( rc != LDAP_SUCCESS ) {
fprintf( stderr, "ldap_create_authzid_control: %s\n",
ldap_err2string( rc ) );
ldap_unbind( ld );
return( 1 );
}
requestctrls[ 0 ] = authzidctrl;
requestctrls[ 1 ] = NULL;
/* Use the authorization ID control for the bind. */
rc = ldap_set_option( ld, LDAP_OPT_SERVER_CONTROLS, &amp;authzidctrl );
if ( rc != LDAP_SUCCESS ) {
ldap_perror( ld, "ldap_set_option" );
return ( 1 );
}
/* Authenticate to the directory, checking for result controls. */
msgid = ldap_simple_bind( ld, ENTRYDN, ENTRYPW );
if ( msgid &lt; 0 ) {
fprintf( stderr, "ldap_simple_bind: %s\n", ldap_err2string( rc ) );
if ( errmsg != NULL &amp;&amp; errmsg != '\0' ) {
fprintf( stderr, "%s\n", errmsg );
}
ldap_unbind( ld );
return ( 1 );
}
rc = ldap_result( ld, msgid, LDAP_MSG_ALL, NULL, &amp;result );
if ( rc &lt; 0 ) {
rc = ldap_get_lderrno( ld, NULL, NULL );
fprintf( stderr, "ldap_result: %s\n", ldap_err2string( rc ) );
ldap_unbind( ld );
return ( 1 );
}
parse_rc = ldap_parse_result( ld, result, &amp;rc, &amp;matched, &amp;errmsg,
&amp;referrals, &amp;resultctrls, 0 );
if ( parse_rc != LDAP_SUCCESS ) {
fprintf( stderr, "ldap_parse_result: %s\n", ldap_err2string( rc ) );
ldap_unbind( ld );
return ( 1 );
}
if ( rc != LDAP_SUCCESS ) {
fprintf( stderr, "ldap_simple_bind: %s\n", ldap_err2string( rc ) );
if ( errmsg != NULL &amp;&amp; errmsg != '\0' ) {
fprintf( stderr, "%s\n", errmsg );
}
}
if ( resultctrls == NULL ) {
fprintf( stderr, "No result control from server.\n" );
ldap_unbind( ld );
return ( 1 );
}
/* Show the authorization ID. */
parse_rc = ldap_parse_authzid_control( ld, resultctrls, &amp;authzid );
if ( parse_rc != LDAP_SUCCESS ) {
fprintf( stderr, "ldap_parse_authzid_control: %s\n",
ldap_err2string( rc ) );
ldap_unbind( ld );
return ( 1 );
}
printf( "DN: %s\n", ENTRYDN );
printf( "Authz ID: %s\n", authzid );
ldap_msgfree( result );
ldap_control_free( authzidctrl );
ldap_controls_free( resultctrls );
ldap_unbind( ld );
return( 0 );
}</programlisting>
</example>
</task>
</sect1>
<sect1 id="controls-get-effective-rights"><title>Using the Get Effective Rights
Request Control With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>LDAP controls</secondary>
<tertiary>get effective rights</tertiary>
</indexterm>
<para>The control with OID <literal>1.3.6.1.4.1.42.2.27.9.5.2</literal>, <literal>
LDAP_CONTROL_GETEFFECTIVERIGHTS_REQUEST</literal>, is the get effective rights
request control. This control lets you request information about the effective
access rights a user has, by performing a search for the <literal>aclRights</literal> and <literal>
aclRightsInfo</literal> attributes.</para>
<task><title>To Get Effective Rights</title>
<procedure>
<step><para>Create a get effective rights request control using the <function>ldap_create_geteffectiveRights_control
</function> function.</para></step>
<step><para>Perform a search with the control, requesting the <literal>aclRights</literal> and <literal>
aclRightsInfo</literal> attributes.</para></step>
<step><para>Read the values of the attributes for the effective rights information.
</para></step>
</procedure>
<example>
<title>Getting Effective Rights</title>
<para>This example gets effective rights for Kirsten Vaughan.</para>
<programlisting>/*
* Get effective rights for another user.
*/
#include "examples.h"
int
main( int argc, char **argv )
{
int version;
LDAP *ld;
int rc;
LDAPControl *gerctrl = NULL;
LDAPControl *requestctrls[ 2 ];
char *authzid;
char **attrlist;
LDAPMessage *result;
LDAPMessage *entry;
char *attr;
BerElement *ber;
char **vals;
int i;
/* 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 as a user. */
if ( ldap_simple_bind_s( ld, USER_DN, USER_PW ) != LDAP_SUCCESS ) {
ldap_perror( ld, "ldap_simple_bind_s" );
return( 1 );
}
/* Create a get effective rights control. */
authzid = "dn: uid=kvaughan,ou=people,dc=example,dc=com";
if ( !( attrlist = (char**)malloc(sizeof(char * [ 2 ]) ) ) ) {
perror( "malloc" );
ldap_unbind( ld );
return ( 1 );
}
attrlist[ 0 ] = "aclRights";
attrlist[ 1 ] = NULL;
rc = ldap_create_geteffectiveRights_control( ld, authzid,
(const char **)&amp;attrlist, 1, &amp;gerctrl );
if ( rc != LDAP_SUCCESS ) {
fprintf( stderr, "ldap_create_geteffectiveRights_control: %s\n",
ldap_err2string( rc ) );
ldap_unbind( ld );
return( 1 );
}
requestctrls[ 0 ] = gerctrl;
requestctrls[ 1 ] = NULL;
/* Read an entry using the control. */
rc = ldap_search_ext_s( ld, ENTRYDN, LDAP_SCOPE_BASE,
"(objectclass=*)", attrlist, 0, requestctrls,
NULL, NULL, 0, &amp;result );
if ( rc != LDAP_SUCCESS ) {
fprintf( stderr, "ldap_search_ext_s: %s\n", ldap_err2string( rc ) );
ldap_unbind( ld );
return( 1 );
}
/* Examine the entry for effective rights. */
printf( "Bind DN: %s\n", ENTRYDN );
printf( "Authz ID: %s\n", authzid );
printf( "***Rights***\n" );
for ( entry = ldap_first_entry( ld, result );
entry != NULL;
entry = ldap_next_entry( ld, entry ) ) {
for ( attr = ldap_first_attribute( ld, entry, &amp;ber );
attr != NULL;
attr = ldap_next_attribute ( ld, entry, ber) ) {
if ( (vals = ldap_get_values( ld, entry, attr ) ) != NULL) {
for ( i = 0; vals[i] != NULL; ++i ) {
printf( "%s: %s\n", attr, vals[i] );
}
ldap_value_free( vals );
}
ldap_memfree( attr );
}
if ( ber != NULL ) {
ber_free( ber, 0 );
}
}
printf( "\n" );
ldap_msgfree( result );
ldap_control_free( gerctrl );
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 the following. Lines are wrapped for readability.</para>
<screen>Bind DN: uid=bjensen, ou=People, dc=example,dc=com
Authz ID: dn: uid=kvaughan,ou=people,dc=example,dc=com
***Rights***
aclRights;entryLevel: add:1,delete:1,read:1,write:1,proxy:0
aclRights;attributeLevel;: search:1,read:1,compare:1,write:1,
selfwrite_add:1,selfwrite_delete:1,proxy:0
aclRights;attributeLevel;dn: uid=kvaughan,ou=people,dc=example,dc=com:
search:1,read:1,compare:1,write:1,selfwrite_add:1,selfwrite_delete:1,
proxy:0
aclRights;attributeLevel;@c : search:1,read:1,compare:1,write:1,
selfwrite_add:1,selfwrite_delete:1,proxy:0</screen>
<para>See your server documentation <?Pub Caret>for information about <literal>aclRights
</literal> and <literal>aclRightsInfo</literal> values.</para></example>
</task>
</sect1>
<sect1 id="controls-real-attrs-only"><title>Using the Real Attributes Only
Request Control With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>LDAP controls</secondary>
<tertiary>real attributes only</tertiary>
</indexterm>
<para>The control with OID <literal>2.16.840.1.113730.3.4.17</literal>, <literal>
LDAP_CONTROL_REAL_ATTRS_ONLY</literal>, is the real attributes only request
control. This control lets you convey to the server to return only real attributes,
attributes that are stored by the directory, during a search.</para>
<para>To retrieve only virtual attributes, see <olink targetptr="controls-virtual-attrs-only">Using the Virtual Attributes Only
Request Control With Directory SDK for C</olink>.</para>
<task><title>To Retrieve Only Real Attributes</title>
<procedure>
<step><para>Create an <structname>LDAPControl</structname> structure with
the OID defined using <literal>LDAP_CONTROL_REAL_ATTRS_ONLY</literal>.</para>
</step>
<step><para>Pass the control in to the server with the search request.</para>
</step>
<step><para>Free the control when finished.</para></step>
</procedure>
<example>
<title>Retrieving Only Real Attributes</title>
<para>This example relies on sample data from <filename>Example-roles.ldif</filename>.
</para>
<programlisting>/*
* Use the control to get only real attributes.
* First load suffix data from Example-roles.ldif.
*/
#include "examples.h"
int
main( int argc, char **argv )
{
LDAPControl *ctrl = NULL;
LDAPControl *requestctrls[ 2 ];
char **attrlist;
int version;
LDAP *ld;
char *target;
int rc;
LDAPMessage *result;
LDAPMessage *entry;
char *dn;
char *attr;
BerElement *ber;
char **vals;
int i;
/* Prepare a real attributes only request control. */
if ( !(ctrl = (LDAPControl *)malloc(sizeof(LDAPControl))) ) {
perror( "malloc" );
return( 1 );
}
ctrl->ldctl_oid = strdup( LDAP_CONTROL_REAL_ATTRS_ONLY );
ctrl->ldctl_iscritical = 1;
requestctrls[ 0 ] = ctrl;
requestctrls[ 1 ] = NULL;
/* Create a list of attributes to retrieve. */
if ( !( attrlist = (char**)malloc(sizeof(char * [ 3 ]) ) ) ) {
perror( "malloc" );
return ( 1 );
}
attrlist[ 0 ] = "cn"; /* Real attribute */
attrlist[ 1 ] = "nsrole"; /* Virtual attribute */
attrlist[ 2 ] = NULL;
/* 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 to read an entry. */
if ( ldap_simple_bind_s( ld, USER_DN, USER_PW ) != LDAP_SUCCESS ) {
ldap_perror( ld, "ldap_simple_bind_s" );
return( 1 );
}
/* Read an entry using the control. */
target = "uid=kvaughan,ou=people,dc=example,dc=com";
rc = ldap_search_ext_s( ld, target, LDAP_SCOPE_BASE, "(objectclass=*)",
attrlist, 0, requestctrls, NULL, NULL, 0, &amp;result );
if ( rc != LDAP_SUCCESS ) {
fprintf( stderr, "ldap_search_ext_s: %s\n", ldap_err2string( rc ) );
ldap_unbind( ld );
return( 1 );
}
/* Examine the results. */
for ( entry = ldap_first_entry( ld, result );
entry != NULL;
entry = ldap_next_entry( ld, entry ) ) {
if ( (dn = ldap_get_dn( ld, entry )) != NULL ) {
printf( "dn: %s\n", dn );
ldap_memfree( dn );
}
for ( attr = ldap_first_attribute( ld, entry, &amp;ber );
attr != NULL;
attr = ldap_next_attribute ( ld, entry, ber) ) {
if ( (vals = ldap_get_values( ld, entry, attr ) ) != NULL) {
for ( i = 0; vals[i] != NULL; ++i ) {
printf( "%s: %s\n", attr, vals[i] );
}
ldap_value_free( vals );
}
ldap_memfree( attr );
}
if ( ber != NULL ) {
ber_free( ber, 0 );
}
}
printf( "\n" );
ldap_msgfree( result );
ldap_control_free( ctrl );
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-roles.ldif</filename>,
the server produces output similar to this:</para>
<screen>dn: uid=kvaughan, ou=People, dc=example,dc=com
cn: Kirsten Vaughan</screen>
</example>
</task>
</sect1>
<sect1 id="controls-virtual-attrs-only"><title>Using the Virtual Attributes
Only Request Control With &DirectorySDKForC;</title>
<indexterm>
<primary>C SDK</primary>
<secondary>LDAP controls</secondary>
<tertiary>virtual attributes only</tertiary>
</indexterm>
<para>The control with OID <literal>2.16.840.1.113730.3.4.19</literal>, <literal>
LDAP_CONTROL_VIRTUAL_ATTRS_ONLY</literal>, is the virtual attributes only
request control. This control lets you convey to the server to return only
virtual attributes during a search. Virtual attribute values are not stored
by the directory, but instead are generated on request.</para>
<para>To retrieve only real attributes, see <olink targetptr="controls-real-attrs-only">Using the Real Attributes Only Request
Control With Directory SDK for C</olink>.</para>
<task><title>To Retrieve Only Virtual Attributes</title>
<procedure>
<step><para>Create an <structname>LDAPControl</structname> structure with
the OID defined using <literal>LDAP_CONTROL_VIRTUAL_ATTRS_ONLY</literal>.</para>
</step>
<step><para>Pass the control in to the server with the search request.</para>
</step>
<step><para>Free the control when finished.</para></step>
</procedure>
<example>
<title>Retrieving Only Virtual Attributes</title>
<para>This example relies on sample data from <filename>Example-roles.ldif</filename>.
</para>
<programlisting>/*
* Use the control to get only virtual attributes.
* First load suffix data from Example-roles.ldif.
*/
#include "examples.h"
int
main( int argc, char **argv )
{
LDAPControl *ctrl = NULL;
LDAPControl *requestctrls[ 2 ];
char **attrlist;
int version;
LDAP *ld;
char *target;
int rc;
LDAPMessage *result;
LDAPMessage *entry;
char *dn;
char *attr;
BerElement *ber;
char **vals;
int i;
/* Prepare a virtual attributes only request control. */
if ( !(ctrl = (LDAPControl *)malloc(sizeof(LDAPControl))) ) {
perror( "malloc" );
return( 1 );
}
ctrl->ldctl_oid = strdup( LDAP_CONTROL_VIRTUAL_ATTRS_ONLY );
ctrl->ldctl_iscritical = 1;
requestctrls[ 0 ] = ctrl;
requestctrls[ 1 ] = NULL;
/* Create a list of attributes to retrieve. */
if ( !( attrlist = (char**)malloc(sizeof(char * [ 3 ]) ) ) ) {
perror( "malloc" );
return ( 1 );
}
attrlist[ 0 ] = "cn"; /* Real attribute */
attrlist[ 1 ] = "nsrole"; /* Virtual attribute */
attrlist[ 2 ] = NULL;
/* 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 to read an entry. */
if ( ldap_simple_bind_s( ld, USER_DN, USER_PW ) != LDAP_SUCCESS ) {
ldap_perror( ld, "ldap_simple_bind_s" );
return( 1 );
}
/* Read an entry using the control. */
target = "uid=kvaughan,ou=people,dc=example,dc=com";
rc = ldap_search_ext_s( ld, target, LDAP_SCOPE_BASE, "(objectclass=*)",
attrlist, 0, requestctrls, NULL, NULL, 0, &amp;result );
if ( rc != LDAP_SUCCESS ) {
fprintf( stderr, "ldap_search_ext_s: %s\n", ldap_err2string( rc ) );
ldap_unbind( ld );
return( 1 );
}
/* Examine the results. */
for ( entry = ldap_first_entry( ld, result );
entry != NULL;
entry = ldap_next_entry( ld, entry ) ) {
if ( (dn = ldap_get_dn( ld, entry )) != NULL ) {
printf( "dn: %s\n", dn );
ldap_memfree( dn );
}
for ( attr = ldap_first_attribute( ld, entry, &amp;ber );
attr != NULL;
attr = ldap_next_attribute ( ld, entry, ber) ) {
if ( (vals = ldap_get_values( ld, entry, attr ) ) != NULL) {
for ( i = 0; vals[i] != NULL; ++i ) {
printf( "%s: %s\n", attr, vals[i] );
}
ldap_value_free( vals );
}
ldap_memfree( attr );
}
if ( ber != NULL ) {
ber_free( ber, 0 );
}
}
printf( "\n" );
ldap_msgfree( result );
ldap_control_free( ctrl );
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-roles.ldif</filename>,
the server produces output similar to this:</para>
<screen>dn: uid=kvaughan, ou=People, dc=example,dc=com
nsrole: cn=directory administrators,dc=example,dc=com
nsrole: cn=hr managers,dc=example,dc=com</screen>
</example>
</task>
</sect1>
</chapter>