Mozilla LDAP SDK Programmer's Guide/Extended Operations With LDAP C SDK

From MozillaWiki
Jump to: navigation, search

This section explains LDAP v3 extended operations. It also explains how to use the extended operations supported by your LDAP server.

How Extended Operations Work With LDAP C SDK

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.

  • The OID of the extended operation that should be performed
  • Data specific to the extended operation

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.

To use extended operations, both the server and the client must understand the specific extended operation to be performed. From the LDAP server perspective, Directory Server supports a server plug-in interface that you can use to add support for extended operations.

Determining the Extended Operations Supported With LDAP C SDK

To determine the extended operations supported by the server, get the root DSE of the server, and check the supportedExtension 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 supportedExtension attribute, the server does not support any extended operations.

Performing an Extended Operation With LDAP C SDK

  • The synchronous ldap_extended_operation_s() function
  • The asynchronous ldap_extended_operation() function

Both of these functions allow you to specify the OID of the extended operation and the data that you want applied to the operation.

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 LDAP_NOT_SUPPORTED result code is returned.


Synchronous Extended Operation


If you want to wait for the results of an LDAP extended operation to complete before continuing, call the synchronous ldap_extended_operation_s() 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.

ldap_extended_operation_s() returns LDAP_SUCCESS if the operation completed successfully, or an error code if a problem occurred. See the documentation for the ldap_extended_operation_s() function for a list of the possible result codes.


Asynchronous Extended Operation


If you want to perform other work in parallel while waiting for an LDAP extended operation to complete, perform the following procedure.

To Perform an Asynchronous Extended Operation

  1. Call the asynchronous ldap_extended_operation() function to send an LDAP extended operation request.
    This function returns an LDAP_SUCCESS 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 msgidp 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 ldap_result() function and pass in this message ID. The function passes back the response in an LDAPMessage structure.
  2. Call the ldap_parse_extended_result() function to parse the LDAPMessage structure and retrieve information from the servers response.
    If the server sent an OID of an extended operation to your client, the OID is passed back as the retoidp argument. If the server sent data to your client, the data is specified in the berval structure passed back as the retdatap argument.
  3. Call the ldap_get_lderrno() function to get the LDAP result code for the operation.
    The function returns an LDAP_SUCCESS result code if the extended operation was performed successfully, or an LDAP error code if a problem occurred. See the documentation for the ldap_extended_operation() function for a list of result codes that the server can return for this operation.

This example client requests an asynchronous extended operation from the server with OID 1.2.3.4.

#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;
}

Performing an LDAP Password Modify Extended Operation With LDAP C SDK

RFC 3062, LDAP Password Modify Extended Operation, describes the extended operation, which is particularly useful for changing expired passwords.

To Perform an LDAP Password Modify Extended Operation

  1. Get a connection to the directory that uses LDAP version 3.
  2. Authenticate to the directory.
    • As an administrator, to be able to reset an expired user password if you do not have the old password
    • Anonymously to reset an expired password if you have the old password
    • As the user herself to change the password that has not yet expired
  3. Modify the password with the synchronous function ldap_passwd_s() or the asynchronous function ldap_passwd() and use ldap_parse_passwd() or ldap_parse_passwd_result() to examine the results.

This example changes a password using ldap_passwd_s().

/*
 * 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 );

When you compile and run this sample program against Directory Server with a suffix that contains data from Example.ldif, the server produces output similar to this:

Successfully changed password for uid=bjensen, ou=People, dc=example,dc=com

Using Start TLS With LDAP C SDK

RFC 4513, Lightweight Directory Access Protocol (LDAP): Authentication Methods and Security Mechanisms, describes the extended operation. Start TLS allows you to connect on a non secure port, and then request transport layer security.

See Starting Transport Layer Security With LDAP C SDK for an example of how to use Start TLS.

Performing a Who Am I? Extended Operation With LDAP C SDK

The Who am I? extended operation allows you to retrieve the authorization identity that is associated with a connection.

This method can involve less code than the standard authorization identity controls that are described in Using the Authorization Identity Bind Request Control With LDAP C SDK.

To Perform a Who Am I? Extended Operation

  1. Get a connection to the directory that uses LDAP version 3.
  2. Use ldap_whoami() and ldap_parse_whoami_result(), or use ldap_whoami_s(), to retrieve the authorization identity.

This example retrieves authorization identity by using ldap_whoami_s().

/*
 * 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 );
}

When you compile and run this sample program against Directory Server with a suffix that contains data from Example.ldif, the server produces output similar to this:

Authorization ID: dn:uid=bjensen,ou=people,dc=example,dc=com