2029 lines
82 KiB
Plaintext
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–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’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 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, &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 &&
|
|
(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>] …</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—Side
|
|
Sorting Control for Direcory SDK for C</title>
|
|
<programlisting>#include <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, &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( &sortkeylist, "sn -givenname" );
|
|
/* Create the sort control. */
|
|
rc = ldap_create_sort_control( ld, sortkeylist, 1, &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, &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, &rc, &matched,
|
|
&errmsg, &referrals, &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 && *errmsg != '\0' ) {
|
|
fprintf( stderr, "%s\n", errmsg );
|
|
}
|
|
ldap_unbind( ld );
|
|
return( 1 );
|
|
}
|
|
parse_rc =
|
|
ldap_parse_sort_control( ld, resultctrls, &rcode, &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 && *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’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’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, &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, &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, &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, &rc, &matched, &errmsg,
|
|
&referrals, &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, &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, &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, &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, &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 < 0 ) {
|
|
fprintf( stderr, "ldap_simple_bind: %s\n", ldap_err2string( rc ) );
|
|
if ( errmsg != NULL && errmsg != '\0' ) {
|
|
fprintf( stderr, "%s\n", errmsg );
|
|
}
|
|
ldap_unbind( ld );
|
|
return ( 1 );
|
|
}
|
|
|
|
rc = ldap_result( ld, msgid, LDAP_MSG_ALL, NULL, &result );
|
|
if ( rc < 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, &rc, &matched, &errmsg,
|
|
&referrals, &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 && 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, &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, &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, &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, &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, &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, &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 < 0 ) {
|
|
fprintf( stderr, "ldap_simple_bind: %s\n", ldap_err2string( rc ) );
|
|
if ( errmsg != NULL && errmsg != '\0' ) {
|
|
fprintf( stderr, "%s\n", errmsg );
|
|
}
|
|
ldap_unbind( ld );
|
|
return ( 1 );
|
|
}
|
|
|
|
rc = ldap_result( ld, msgid, LDAP_MSG_ALL, NULL, &result );
|
|
if ( rc < 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, &rc, &matched, &errmsg,
|
|
&referrals, &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 && 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, &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, &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 **)&attrlist, 1, &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, &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, &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, &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, &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, &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, &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, &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, &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>
|