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