# Extended Operations With &DirectorySDKForC;

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

This chapter covers the following topics:

- How Extended Operations Work With Directory SDK for C

- Determining the Extended Operations Supported With Directory SDK for C

- Performing an Extended Operation With Directory SDK for C

- Performing an LDAP Password Modify Extended Operation With Directory SDK for C

- Using Start TLS With Directory SDK for C

- Performing a Who Am I? Extended Operation With Directory SDK for C

## How Extended Operations Work With Directory SDK for C

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.

Within the request, the client specifies the following:

- 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, &cnDirectoryServer; supports a server plug-in interface that you can use to add support for extended operations.

## Determining the Extended Operations Supported With &DirectorySDKForC;

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. See To Get the Root DSE for instructions on reading that entry.

## Performing an Extended Operation With &DirectorySDKForC;

To perform an extended operation, for which no specialized API exists, call one of the following functions:

- 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. For details, see Specifying the LDAP Version of Your Client.

### 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 server’s 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.

#### Perform an Asynchronous Extended 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 &DirectorySDKForC;

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.

3. As an administrator, to be able to reset an expired user password if you do not have the old password

4. Anonymously to reset an expired password if you have the old password

5. As the user herself to change the password that has not yet expired

6. 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.

### Performing an LDAP Password Modify Extended Operation

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 &cnDirectoryServer; 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 &DirectorySDKForC;

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 Directory SDK for C for an example of how to use Start TLS.

## Performing a Who Am I? Extended Operation With &DirectorySDKForC;

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 Directory SDK for C.

## 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.

### Getting 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 &cnDirectoryServer; 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