Mozilla LDAP SDK Programmer's Guide/Adding, Updating, and Deleting Entries With LDAP C SDK

From MozillaWiki
Jump to: navigation, search

This section explains how to use LDAP C API functions to add, update, delete, and rename entries.

Specifying Entry Information With LDAP C SDK

The type of attribute that you are working with. For example, the sn attribute or the telephoneNumber attribute.

  • The values that you are adding, or replacing in the attribute.
  • The operation that you are performing when modifying an existing entry. In other words, determine whether you are adding, modifying, or deleting the attribute in the existing entry.
  • To specify this information, you use an LDAPMod structure as shown here.
typedef struct ldapmod {
  int mod_op;
  char *mod_type;
  union {
    char **modv_strvals;
    struct berval **modv_bvals;
  } mod_vals;
#define mod_values        mod_vals.modv_strvals
#define mod_bvalues       mod_vals.modv_bvals
} LDAPMod;

The following list details the fields in the LDAPMod data structure.

  • mod_op
    • LDAP_MOD_ADD adds a value to the attribute.
    • LDAP_MOD_DELETE removes a value from the attribute.
    • LDAP_MOD_REPLACE replaces all existing values of the attribute.
      Furthermore, if you specify binary values in the mod_bvalues field, use the bitwise or operator, |, to combine LDAP_MOD_BVALUES with the operation type:
      mod->mod_op = LDAP_MOD_ADD | LDAP_MOD_BVALUES
      If you are using the structure to add a new entry, you can specify 0 for the mod_op field, unless you are adding binary values and need to specify LDAP_MOD_BVALUES.
  • mod_type
    Attribute type that you want to add, delete, or replace, such as sn or telephoneNumber.
  • mod_values
    Pointer to a NULL terminated array of string values for the attribute.
  • mod_bvalues
    Pointer to a NULL terminated array of berval structures for the attribute.

The following precautions pertain to entry modifications and the fields detailed in this list.

  • If you specify LDAP_MOD_DELETE in the mod_op field to remove all values in an attribute, the attribute is removed from the entry.
  • If you specify LDAP_MOD_DELETE in the mod_op field and NULL in the mod_values field, the attribute is removed from the entry.
  • If you specify LDAP_MOD_REPLACE in the mod_op field and NULL in the mod_values field, the attribute is removed from the entry.
  • If you specify LDAP_MOD_REPLACE in the mod_op field, but the attribute does not exist in the entry, the attribute is added to the entry.
  • If you specify LDAP_MOD_ADD in the mod_op field, but the attribute does not exist in the entry, the attribute is added to the entry.

If you allocate memory for the structures yourself, free the structures when you finish by calling the ldap_mods_free() function.

Adding an Entry With LDAP C SDK

The following procedure provides the general steps for adding a new entry to the directory.

To Add a New Entry

  1. Use the LDAPMod structure to specify the name and values of each attribute.
  2. Create an array of LDAPMod structures to represent the attributes in the entry.
  3. Call the ldap_add_ext() or ldap_add_ext_s() function, passing in the array of LDAPMod structures and a distinguished name (DN) for the entry.
  4. Call the ldap_mods_free function to free any LDAPMod structures that you allocated.


Specifying Values for Attributes


You can specify a value for an attribute in three ways. You can specify a single value. You can specify multiple values. You can add binary data as the value of an attribute.


Specifying a Single Value in an Attribute


To specify a value in an attribute, set the mod_op, mod_type, and mod_values fields in an LDAPMod structure. This example sets up the structure for the sn attribute.

#include "ldap.h"

LDAPMod attribute1;
char *sn_values[] = { "Jensen", NULL };

attribute1.mod_op = 0;
attribute1.mod_type = "sn";
attribute1.mod_values = sn_values;

Because you are specifying an attribute for a new entry, rather than for an existing entry, you can set the mod_op field to 0. For an existing entry, the mod_op field identifies the type of change you are making to the entry.


Specifying Multiple Values in an Attribute


If an attribute has more than one value, specify the values in the mod_values array. This example specifies two values for the cn attribute.

#include "ldap.h"

LDAPMod attribute2, attribute3;
char *cn_values[] = { "Barbara Jensen", "Babs Jensen", NULL };
char *objectClass_values[] = { "top", "person",
   "organizationalPerson", "inetOrgPerson", NULL };

attribute2.mod_op = 0;
attribute2.mod_type = "cn";
attribute2.mod_values = cn_values;
attribute3.mod_op = 0;
attribute3.mod_type = "objectClass";
attribute3.mod_values = objectClass_values;

Specifying Binary Data as the Value of an Attribute


If the attribute contains binary data rather than string values, specify the data in a berval structure similar to this.

struct berval {
   unsigned long bv_len;
   char *bv_val;
}

The berval structure fields and field descriptions are as follows:

bv_len: The length of the data

bv_val: A pointer to the binary data

After creating the berval structures for the binary data, you may use the structures.

To Use berval Structures

  1. Add the berval structures to the mod_bvalues field in the LDAPMod structure.
  2. Use the bitwise or operator, |, to combine the value of the mod_op field with LDAP_MOD_BVALUES.
    When adding a new entry, you set the mod_op field to LDAP_MOD_BVALUES because the mod_op field is 0 in this case.
    For example, suppose the file my_photo.jpg contains a JPEG photograph of Barbara Jensen. The following example sets the jpegPhoto attribute to the JPEG data of the photograph.
#include <stdio.h>
#include <sys/stat.h>
#include "ldap.h"

char *photo_data;
FILE *fp;
struct stat st;
LDAPMod attribute4;
struct berval photo_berval;
struct berval *jpegPhoto_values[2];
/* Get information about the JPEG file, including its size. */
if ( stat( "my_photo.jpg", st ) != 0 ) {
  perror( "stat" );
  return( 1 );
}

/* Open the JPEG file and read it into memory. */
if ( ( fp = fopen( "my_photo.jpg", "rb" ) ) == NULL ) {
  perror( "fopen" );
  return( 1 );
}
if ( ( ( photo_data = ( char * )malloc( st.st_size ) ) == NULL ) ||
      ( fread ( photo_data, st.st_size, 1, fp ) != 1 ) ) {
  perror( photo_data ? "fread" : "malloc" );
  return( 1 );
}

fclose( fp );

attribute4.mod_op = LDAP_MOD_BVALUES;
attribute4.mod_type = "jpegPhoto";
photo_berval.bv_len = st.st_size;
photo_berval.bv_val = photo_data;
jpegPhoto_values[0] = photo_berval;
jpegPhoto_values[1] = NULL;
attribute4.mod_values = jpegPhoto_values;

Specifying Attributes in the Entry


After specifying values for attributes in LDAPMod structures, as described in Specifying Values for Attributes, you need to construct an array of these structures. You then pass a pointer to this array as a parameter to the function for creating a new entry.

Make sure you create LDAPMod structures for all required attributes in the new entry.

The following example creates an array of LDAPMod structures.


#include "ldap.h"
LDAPMod *list_of_mods[5]
LDAPMod attribute1, attribute2, attribute3, attribute4;

/* Code for filling the LDAPMod structures with values */

list_of_mods[0] = attribute1;
list_of_mods[1] = attribute2;
list_of_mods[2] = attribute3;
list_of_mods[3] = attribute4;
list_of_mods[4] = NULL;

Adding the Entry to the Directory


  • The synchronous ldap_add_ext_s() function
  • The asynchronous ldap_add_ext() function

If you have allocated LDAPMod structures yourself, you should free the structures when you are done. Call the ldap_mods_free() function to free LDAPMod structures.


Synchronous Add Operation


If you want to wait for the results of the add operation to complete before continuing, call the synchronous ldap_add_ext_s() function. This function sends an LDAP add request to the server. The function also blocks other work until the server sends the results of the operation back to your client. The ldap_add_ext_s() function returns LDAP_SUCCESS if the operation completed successfully, or an error code if a problem occurred.

The following example calls the synchronous ldap_add_ext_s() function to add the user William Jensen to the directory.

#include <stdio.h>
#include "ldap.h"

#define NEW_DN "uid=wbjensen,ou=People,dc=example,dc=com"

LDAP         *ld;
LDAPMod      **mods;
char         *matched_msg = NULL, *error_msg = NULL;
int         rc;

/* Perform the add operation. */
rc = ldap_add_ext_s( ld, NEW_DN, mods, NULL, NULL );
if ( rc != LDAP_SUCCESS ) {
  fprintf( stderr, "ldap_add_ext_s: %s\n", ldap_err2string( rc ) );
  ldap_get_lderrno( ld, matched_msg, error_msg );
  if ( error_msg != NULL  *error_msg != '\0' ) {
    fprintf( stderr, "%s\n", error_msg );
  }
  if ( matched_msg != NULL  *matched_msg != '\0' ) {
    fprintf( stderr,
      "Part of the DN that matches an existing entry: %s\n",
      matched_msg );
  }
} else {
  printf( "%s added successfully.\n", NEW_DN );
}

The following sample program calls the synchronous ldap_add_ext_s() function to add a new user to the directory.

#include <stdio.h>
#include "ldap.h"
/* Change these as needed. */
#define HOSTNAME "localhost"
#define PORTNUMBER LDAP_PORT
#define BIND_DN "cn=Directory Manager"
#define BIND_PW "23skidoo"
#define NEW_DN "uid=wbjensen,ou=People,dc=example,dc=com"
#define  NUM_MODS 5
int
main( int argc, char **argv )
{
  LDAP           *ld;
  LDAPMod        **mods;
  char           *matched_msg = NULL, *error_msg = NULL;
    int          i, rc;
  char *object_vals[] = { "top", "person", "organizationalPerson",
    "inetOrgPerson", NULL };

char *cn_vals[] = { "William B Jensen", "William Jensen", "Bill Jensen",
    NULL };
    char *sn_vals[] = { "Jensen", NULL };
    char *givenname_vals[] = { "William", "Bill", NULL };
    char *telephonenumber_vals[] = { "+1 415 555 1212", NULL };
    /* Get a handle to an LDAP connection. Use prldap_init() for IPv6. */
    if ( (ld = ldap_init( HOSTNAME, PORTNUMBER )) == NULL ) {
    perror( "ldap_init" );
    return( 1 );
    }
    /* Bind to the server as the Directory Manager. */
    rc = ldap_simple_bind_s( ld, BIND_DN, BIND_PW );
  if ( rc != LDAP_SUCCESS ) {
    fprintf( stderr, "ldap_simple_bind_s: %s\n", ldap_err2string( rc ) );
    ldap_get_lderrno( ld, matched_msg, error_msg );
    if ( error_msg != NULL  *error_msg != '\0' ) {
      fprintf( stderr, "%s\n", error_msg );
    }
    if ( matched_msg != NULL  *matched_msg != '\0' ) {
      fprintf( stderr,
        "Part of the DN that matches an existing entry: %s\n",
        matched_msg );
    }
    ldap_unbind_s( ld );
    return( 1 );
    }
    /* Construct the array of LDAPMod structures representing the attributes
     of the new entry. */
    mods = ( LDAPMod ** ) malloc(( NUM_MODS + 1 ) * sizeof( LDAPMod * ));
    if ( mods == NULL ) {
    fprintf( stderr, "Cannot allocate memory for mods array\n" );
    exit( 1 );
    }
    for ( i = 0; i  NUM_MODS; i++ ) {
    if (( mods[ i ] = ( LDAPMod * ) malloc( sizeof( LDAPMod ))) == NULL ) {
      fprintf( stderr, "Cannot allocate memory for mods element\n" );
      exit( 1 );
    }
    }
    mods[ 0 ]->mod_op = 0;
    mods[ 0 ]->mod_type = "objectclass";
    mods[ 0 ]->mod_values = object_vals;
    mods[ 1 ]->mod_op = 0;
    mods[ 1 ]->mod_type = "cn";
    mods[ 1 ]->mod_values = cn_vals;
    mods[ 2 ]->mod_op = 0;
    mods[ 2 ]->mod_type = "sn";
    mods[ 2 ]->mod_values = sn_vals;
    mods[ 3 ]->mod_op = 0;
    mods[ 3 ]->mod_type = "givenname";
    mods[ 3 ]->mod_values = givenname_vals;
    mods[ 4 ]->mod_op = 0;
    mods[ 4 ]->mod_type = "telephonenumber";
    mods[ 4 ]->mod_values = telephonenumber_vals;
    mods[ 5 ] = NULL;
    /* Perform the add operation. */
    rc = ldap_add_ext_s( ld, NEW_DN, mods, NULL, NULL );
  if ( rc != LDAP_SUCCESS ) {
    fprintf( stderr, "ldap_add_ext_s: %s\n", ldap_err2string( rc ) );
    ldap_get_lderrno( ld, matched_msg, error_msg );
    if ( error_msg != NULL  *error_msg != '\0' ) {
      fprintf( stderr, "%s\n", error_msg );
    }
    if ( matched_msg != NULL  *matched_msg != '\0' ) {
      fprintf( stderr,
        "Part of the DN that matches an existing entry: %s\n",
        matched_msg );
    }
    } else {
    printf( "%s added successfully.\n", NEW_DN );
  }
  ldap_unbind_s( ld );
  for ( i = 0; i  NUM_MODS; i++ ) {
    free( mods[ i ] );
  }
  free( mods );
  return 0;
}

Asynchronous Add Operation


If you want to perform other work while waiting for the entry to be added, call the asynchronous ldap_add_ext() function. This function sends an LDAP add request to the server and returns an LDAP_SUCCESS result code if the request was successfully sent, or an LDAP result code if an error occurred.

The ldap_add_ext() function passes back a message ID identifying the add operation. To determine whether the server sent a response for this operation to your client, call the ldap_result() function and pass in this message ID. The ldap_result() function uses the message ID to determine if the server sent the results of the add operation. The ldap_result() function passes back the results in an LDAPMessage structure. You can call the ldap_parse_result() function to parse the LDAPMessage structure to determine if the operation was successful.

The following example calls the asynchronous ldap_add_ext() function to add the user William Jensen to the directory.

#include <stdio.h>
#include "ldap.h"

#define NEW_DN "uid=wbjensen,ou=People,dc=example,dc=com"


LDAP           *ld;
LDAPMessage    *res;
LDAPControl    **serverctrls;
char           *matched_msg = NULL, *error_msg = NULL;
char           **referrals;
int            i, rc, parse_rc, msgid, finished = 0;

/* Timeout period for the ldap_result() function to wait for results. */
struct timeval  zerotime;
zerotime.tv_sec = zerotime.tv_usec = 0L;

/* Send the LDAP add request. */
rc = ldap_add_ext( ld, NEW_DN, mods, NULL, NULL, msgid );
if ( rc != LDAP_SUCCESS ) {
  fprintf( stderr, "ldap_add_ext: %s\n", ldap_err2string( rc ) );
  ldap_unbind( ld );
  return( 1 );
}

/* Poll the server for the results of the add operation. */
while ( !finished ) {
  rc = ldap_result( ld, msgid, 0, zerotime, res );
  switch ( rc ) {
  case -1:
    /* An error occurred. */
    rc = ldap_get_lderrno( ld, NULL, NULL );
    fprintf( stderr, "ldap_result: %s\n", ldap_err2string( rc ) );
    ldap_unbind( ld );
    return( 1 );
  case 0:
    /* The timeout period specified by zerotime was exceeded,
      so call ldap_result() again and continue polling. */
    break;
  default:
    /* The function has retrieved the results of the add operation. */
    finished = 1;

    /* Parse the result to determine the result of
      the add operation. */
    parse_rc = ldap_parse_result( ld, res, rc, matched_msg,
      error_msg, referrals, serverctrls, 1 );
    if ( parse_rc != LDAP_SUCCESS ) {
      fprintf( stderr, "ldap_parse_result: %s\n",
        ldap_err2string( parse_rc ) );
      ldap_unbind( ld );
      return( 1 );
    }

    /* Check the results of the LDAP add operation. */
    if ( rc != LDAP_SUCCESS ) {
      fprintf( stderr, "ldap_add_ext: %s\n", ldap_err2string( rc ) );
      if ( error_msg != NULL  *error_msg != '\0' ) {
        fprintf( stderr, "%s\n", error_msg );
      }
      if ( matched_msg != NULL  *matched_msg != '\0' ) {
        fprintf( stderr,
          "Part of the DN that matches an existing entry: %s\n",
          matched_msg );
      }
    } else {
      printf( "%s added successfully.\n", NEW_DN );
    }
  }
}

The following sample program calls the asynchronous ldap_add_ext() function to add a new user to the directory.

#include <stdio.h>
#include "ldap.h"
void do_other_work();
int global_counter = 0;
void free_mods( LDAPMod **mods );
/* Change these as needed. */
#define HOSTNAME "localhost"
#define PORTNUMBER LDAP_PORT
#define BIND_DN "cn=Directory Manager"
#define BIND_PW "23skidoo"
#define NEW_DN "uid=wbjensen,ou=People,dc=example,dc=com"
#define  NUM_MODS 5
int
main( int argc, char **argv )
{
    LDAP      *ld;
    LDAPMessage    *res;
    LDAPMod      **mods;
  LDAPControl    **serverctrls;
  char           *matched_msg = NULL, *error_msg = NULL;
  char           **referrals;
    int        i, rc, parse_rc, msgid, finished = 0;
    struct timeval  zerotime;
    char *object_vals[] = { "top", "person", "organizationalPerson", 
                            "inetOrgPerson", NULL };
    char *cn_vals[] = { "William B Jensen", "William Jensen",
                        "Bill Jensen", NULL };
    char *sn_vals[] = { "Jensen", NULL };
    char *givenname_vals[] = { "William", "Bill", NULL };
    char *telephonenumber_vals[] = { "+1 415 555 1212", NULL };
    zerotime.tv_sec = zerotime.tv_usec = 0L;
    /* Get a handle to an LDAP connection. Use prldap_init() for IPv6. */
    if ( (ld = ldap_init( HOSTNAME, PORTNUMBER )) == NULL ) {
    perror( "ldap_init" );
    return( 1 );
    }
    /* Bind to the server as the Directory Manager. */
    rc = ldap_simple_bind_s( ld, BIND_DN, BIND_PW );
  if ( rc != LDAP_SUCCESS ) {
    fprintf( stderr, "ldap_simple_bind_s: %s\n", ldap_err2string( rc ) );
    ldap_get_lderrno( ld, matched_msg, error_msg );
    if ( error_msg != NULL  *error_msg != '\0' ) {
      fprintf( stderr, "%s\n", error_msg );
    }
    if ( matched_msg != NULL  *matched_msg != '\0' ) {
      fprintf( stderr,
        "Part of the DN that matches an existing entry: %s\n",
        matched_msg );
    }
    ldap_unbind_s( ld );
    return( 1 );
    }
    /* Construct the array of LDAPMod structures representing the attributes
     of the new entry. */
    mods = ( LDAPMod ** ) malloc(( NUM_MODS + 1 ) * sizeof( LDAPMod * ));
    if ( mods == NULL ) {
    fprintf( stderr, "Cannot allocate memory for mods array\n" );
    exit( 1 );
    }
    for ( i = 0; i  NUM_MODS; i++ ) {
    if (( mods[ i ] = ( LDAPMod * ) malloc( sizeof( LDAPMod ))) == NULL ) {
      fprintf( stderr, "Cannot allocate memory for mods element\n" );
      exit( 1 );
    }
    }
    mods[ 0 ]->mod_op = 0;
    mods[ 0 ]->mod_type = "objectclass";
    mods[ 0 ]->mod_values = object_vals;
    mods[ 1 ]->mod_op = 0;
    mods[ 1 ]->mod_type = "cn";
    mods[ 1 ]->mod_values = cn_vals;
    mods[ 2 ]->mod_op = 0;
    mods[ 2 ]->mod_type = "sn";
    mods[ 2 ]->mod_values = sn_vals;
    mods[ 3 ]->mod_op = 0;
    mods[ 3 ]->mod_type = "givenname";
    mods[ 3 ]->mod_values = givenname_vals;
    mods[ 4 ]->mod_op = 0;
    mods[ 4 ]->mod_type = "telephonenumber";
    mods[ 4 ]->mod_values = telephonenumber_vals;
    mods[ 5 ] = NULL;
    /* Send the LDAP add request. */
    rc = ldap_add_ext( ld, NEW_DN, mods, NULL, NULL, msgid );
  if ( rc != LDAP_SUCCESS ) {
    fprintf( stderr, "ldap_add_ext: %s\n", ldap_err2string( rc ) );
    ldap_unbind( ld );
    free_mods( mods );
    return( 1 );
    }
    /* Poll the server for the results of the add operation. */
    while ( !finished ) {
    rc = ldap_result( ld, msgid, 0, zerotime, res );
    switch ( rc ) {
    case -1:
      /* An error occurred. */
      rc = ldap_get_lderrno( ld, NULL, NULL );
      fprintf( stderr, "ldap_result: %s\n", ldap_err2string( rc ) );
      ldap_unbind( ld );
      free_mods( mods );
      return( 1 );
    case 0:
      /* The timeout period specified by zerotime was exceeded.
         This means that the server has still not yet sent the
         results of the add operation back to your client.
         Break out of this switch statement, and continue calling
         ldap_result() to poll for results. */
      break;
    default:
      /* The function has retrieved the results of the add operation
         from the server. */
      finished = 1;
      /* Parse the results received from the server. Note the last
         argument is a non-zero value, which indicates that the
         LDAPMessage structure will be freed when done.  (No need
         to call ldap_msgfree().) */
      parse_rc =
        ldap_parse_result( ld, res, rc, matched_msg,
                           error_msg, referrals, serverctrls, 1 );
      if ( parse_rc != LDAP_SUCCESS ) {
        fprintf( stderr,
                 "ldap_parse_result: %s\n", 
                 ldap_err2string( parse_rc ) );
        ldap_unbind( ld );
        free_mods( mods );
        return( 1 );
      }
      /* Check the results of the LDAP add operation. */
      if ( rc != LDAP_SUCCESS ) {
        fprintf( stderr, "ldap_add_ext: %s\n", ldap_err2string( rc ) );
        if ( error_msg != NULL  *error_msg != '\0' ) {
          fprintf( stderr, "%s\n", error_msg );
        }
        if ( matched_msg != NULL  *matched_msg != '\0' ) {
          fprintf( stderr,
            "Part of the DN that matches an existing entry: %s\n",
            matched_msg );
        }
      } else {
        printf( "%s added successfully.\n"
          "Counted to %d while waiting for the add operation.\n",
          NEW_DN, global_counter );
      }
    }
    /* Do other work while waiting for the results of the add operation. */
    if ( !finished ) {
      do_other_work();
    }
  }
  ldap_unbind( ld );
  free_mods( mods );
  return 0;
}
/*
 * Free a mods array.
 */
void
free_mods( LDAPMod **mods )
{
    int i;
    for ( i = 0; i  NUM_MODS; i++ ) {
  free( mods[ i ] );
    }
    free( mods );
}

/*
 * Perform other work while polling for results.
 * This doesn't do anything useful, but it could.
 */
void
do_other_work()
{
    global_counter++;
}

Modifying an Entry With LDAP C SDK

The following procedure provides the general steps for modifying an entry.

To Modify an Entry

  1. Use the LDAPMod structure to specify a change to an attribute.
  2. Create an array of LDAPMod structures that represent the changes that need to be made.
  3. Call the ldap_modify_ext() or ldap_modify_ext_s() function, passing in the array of LDAPMod structures and the DN of the entry that you want modified.
  4. Call the ldap_mods_free() function to free any LDAPMod structures that you allocated.


Types of Modifications


You can modify an entry in various ways. The following sections explain the types of modifications.


Replacing the Values of an Attribute


  • Set the mod_type field to the attribute type that you want to change, such as telephoneNumber.
  • Set the mod_values field to the new values of the attribute.
  • Set the value of the mod_op field to LDAP_MOD_REPLACE.

The following code specifies a change that replaces the values of the telephoneNumber attribute.

#include "ldap.h"
LDAPMod attribute1;
char *telephoneNumber_values[] = { "+1 800 555 1212", NULL };
attribute1.mod_type = "telephoneNumber";
attribute1.mod_op = LDAP_MOD_REPLACE;
attribute1.mod_values = telephoneNumber_values;
  • Use the mod_bvalues field rather than the mod_values field.
  • Use the bitwise or operator, |, to combine the value LDAP_MOD_BVALUES with the value of the mod_op field.

Note: If you specify an attribute that does not exist in the entry, the attribute is added to the entry.

You can set a NULL value for the attribute either by setting the mod_values field to NULL or by setting the mod_bvalues field to NULL. When the mod_op field also contains LDAP_MOD_BVALUES, the attribute is removed from the entry.


Removing Values From an Attribute


  • Set the mod_type field to the attribute type that contains the values to remove such as facsimileTelephoneNumber.
  • Set the mod_values field to the values that you want removed from the attribute.
  • Set the value of the mod_op field to LDAP_MOD_DELETE.
    The following code specifies the removal of one of the values of the facsimileTelephoneNumber attribute in the entry.
include "ldap.h"
LDAPMod attribute2;
char *fax_values[] = { "+1 800 555 1212", NULL };
attribute2.mod_type = "facsimileTelephoneNumber";
attribute2.mod_op = LDAP_MOD_DELETE;
attribute2.mod_values = fax_values;
  • Use the mod_bvalues field rather than the mod_values field.
  • Use the bitwise or operator, |, to combine the value LDAP_MOD_BVALUES with the value of the mod_op field.

Note: If you remove all values from the attribute, the attribute is removed from the entry.

You can set a NULL value for the attribute either by setting the mod_values field to NULL, or by setting the mod_bvalues field to NULL. When the mod_op field then contains LDAP_MOD_BVALUES, the attribute is removed from the entry.


Adding Values to an Attribute


  • Set the mod_type field to the attribute type that you want to add values to, such as audio.
  • Set the mod_values field to the new values of the attribute.
  • Set the value of the mod_op field to LDAP_MOD_ADD.
  • Use the mod_bvalues field rather than the mod_values field, and put the values in berval structures.
  • Use the bitwise or operator, |, to combine the value LDAP_MOD_BVALUES with the value of the mod_op field.

If the attribute does not already exist in the entry, the attribute is added to the entry.

The following code adds values to the audio attribute of an entry.

#include <stdio.h>
#include <sys/stat.h>
#include "ldap.h"

char *audio_data;
FILE *fp;
struct stat st;
LDAPMod attribute3;
struct berval audio_berval;
struct berval *audio_values[2];

/* Get information about the audio file, including its size. */
if ( stat( "my_sounds.au", st ) != 0 ) {
  perror( "stat" );
  return( 1 );
}

/* Open the audio file and read it into memory. */
if ( ( fp = fopen( "my_sounds.au", "rb" ) ) == NULL ) {
  perror( "fopen" );
  return( 1 );
}

if ( ( ( audio_data = ( char * )malloc( st.st_size ) ) == NULL ) ||
      ( fread ( audio_data, st.st_size, 1, fp ) != 1 ) ) {
  perror( audio_data ? "fread" : "malloc" );
  return( 1 );
}

fclose( fp );
attribute3.mod_op = LDAP_MOD_ADD | LDAP_MOD_BVALUES;
attribute3.mod_type = "audio";
audio_berval.bv_len = st.st_size;
audio_berval.bv_val = audio_data;
audio_values[0] = audio_berval;
audio_values[1] = NULL;
attribute3.mod_values = audio_values;

Removing an Attribute With LDAP C SDK


  • Remove all values from the attribute.
  • Set the mod_op field to LDAP_MOD_REPLACE or LDAP_MOD_DELETE, and specify NULL for the mod_values field.


Adding an Attribute With LDAP C SDK


If you add or replace values in an attribute that does not yet exist in the entry, the attribute is added to the entry.


Creating an Array of Changes


After specifying the changes to attribute values in LDAPMod structures, you need to construct an array of these structures. You pass a pointer to this array as a parameter to the function for modifying the entry. The following example creates an array of LDAPMod structures.

#include "ldap.h"

LDAPMod *list_of_mods[4]
LDAPMod attribute1, attribute2, attribute3;

/* Code for filling the LDAPMod structures with values */

list_of_mods[0] = attribute1;
list_of_mods[1] = attribute2;
list_of_mods[2] = attribute3;
list_of_mods[3] = NULL;

Modifying an Entry in the Directory With LDAP C SDK


  • The synchronous ldap_modify_ext_s() function
  • The asynchronous ldap_modify_ext() function


Synchronous Modify Operation


If you want to wait for the results of the modify operation to complete before continuing, call the synchronous ldap_modify_ext_s() function. The function sends a modify request to the server. Also, the function blocks all work until the server sends the results of the operation back to your client. The function returns LDAP_SUCCESS if the operation completed successfully, or an error code if a problem occurred.

The following example calls the synchronous ldap_modify_ext_s() function to modify the entry for the user William Jensen in the directory.

#include <stdio.h>
#include "ldap.h"

#define MODIFY_DN "uid=wbjensen,ou=People,dc=example,dc=com"

LDAP      *ld;
LDAPMod   *mods[ 3 ];
char      *matched_msg = NULL, *error_msg = NULL;
int        rc;

/* Perform the modify operation. */
rc = ldap_modify_ext_s( ld, MODIFY_DN, mods, NULL, NULL );
if ( rc != LDAP_SUCCESS ) {
  fprintf( stderr, "ldap_modify_ext_s: %s\n", ldap_err2string( rc ) );
  ldap_get_lderrno( ld, matched_msg, error_msg );
  if ( error_msg != NULL  *error_msg != '\0' ) {
    fprintf( stderr, "%s\n", error_msg );
  }
  if ( matched_msg != NULL  *matched_msg != '\0' ) {
    fprintf( stderr,
      "Part of the DN that matches an existing entry: %s\n",
      matched_msg );
  }
} else {
  printf( "%s modified successfully.\n", MODIFY_DN );
}
ldap_unbind_s( ld );

The following sample program calls the synchronous ldap_modify_ext_s() function to modify a user entry in the directory. The program replaces the values of the mail attribute and adds a description attribute to the entry.

#include <stdio.h>
#include <time.h>
#include "ldap.h"
/* Change these as needed. */
#define HOSTNAME "localhost"
#define PORTNUMBER LDAP_PORT
#define BIND_DN "cn=Directory Manager"
#define BIND_PW "23skidoo"
#define MODIFY_DN "uid=wbjensen,ou=People,dc=example,dc=com"
int
main( int argc, char **argv )
{
  LDAP         *ld;
  LDAPMod      mod0, mod1;
  LDAPMod      *mods[ 3 ];
  char         *matched_msg = NULL, *error_msg = NULL;
  char         *vals0[ 2 ], *vals1[ 2 ];
  time_t       now;
  char         buf[ 128 ];
  int          rc;
/* Get a handle to an LDAP connection. Use prldap_init() for IPv6. */
  if ( (ld = ldap_init( HOSTNAME, PORTNUMBER )) == NULL ) {
    perror( "ldap_init" );
    return( 1 );
  }
/* Bind to the server as the Directory Manager. */
  rc = ldap_simple_bind_s( ld, BIND_DN, BIND_PW );
  if ( rc != LDAP_SUCCESS ) {
    fprintf( stderr, "ldap_simple_bind_s: %s\n", ldap_err2string( rc ) );
    ldap_get_lderrno( ld, matched_msg, error_msg );
    if ( error_msg != NULL  *error_msg != '\0' ) {
      fprintf( stderr, "%s\n", error_msg );
    }
    if ( matched_msg != NULL  *matched_msg != '\0' ) {
      fprintf( stderr,
        "Part of the DN that matches an existing entry: %s\n",
        matched_msg );
    }
    ldap_unbind_s( ld );
    return( 1 );
  }
/* Construct the array of LDAPMod structures representing the
   changes that you want to make to attributes in the entry. */
/* Specify the first modification, which replaces all values of the
mail attribute with the value "wbj@example.com". */
  mod0.mod_op = LDAP_MOD_REPLACE;
  mod0.mod_type = "mail";
  vals0[0] = "wbj@example.com";
  vals0[1] = NULL;
  mod0.mod_values = vals0;
/* Specify the second modification, which adds a value to the
   description attribute. If this attribute does not yet exist,
   the attribute ia added to the entry. */
  mod1.mod_op = LDAP_MOD_ADD;
  mod1.mod_type = "description";
  time( now );
  sprintf( buf, "This entry was modified with the modattrs program on %s",
  ctime( now ));
/* Get rid of \n which ctime put on the end of the time string */
  if ( buf[ strlen( buf ) - 1 ] == '\n' ) {
    buf[ strlen( buf ) - 1 ] = '\0';
  }
  vals1[ 0 ] = buf;
  vals1[ 1 ] = NULL;
  mod1.mod_values = vals1;
  mods[ 0 ] = mod0;
  mods[ 1 ] = mod1;
  mods[ 2 ] = NULL;
/* Perform the modify operation. */
  rc = ldap_modify_ext_s( ld, MODIFY_DN, mods, NULL, NULL );
  if ( rc != LDAP_SUCCESS ) {
    fprintf( stderr, "ldap_modify_ext_s: %s\n", ldap_err2string( rc ) );
    ldap_get_lderrno( ld, matched_msg, error_msg );
    if ( error_msg != NULL  *error_msg != '\0' ) {
      fprintf( stderr, "%s\n", error_msg );
    }
    if ( matched_msg != NULL  *matched_msg != '\0' ) {
      fprintf( stderr,
        "Part of the DN that matches an existing entry: %s\n",
        matched_msg );
    }
  } else {
    printf( "%s modified successfully.\n", MODIFY_DN );
  }
  ldap_unbind_s( ld );
  return 0;
}

Asynchronous Modify Operation


If you want to perform other work in parallel while waiting for the entry to be modified, call the asynchronous ldap_modify_ext() function. This function sends a modify request to the server and returns an LDAP_SUCCESS result code if the request was successfully sent, or an LDAP result code if an error occurred.

The ldap_modify_ext() function passes back a message ID identifying the modify operation. To determine whether the server sent a response for this operation to your client, call the ldap_result() function and pass in this message ID. The ldap_result() function uses the message ID to determine if the server sent the results of the modify operation. The ldap_result() function passes back the results in an LDAPMessage structure. You can call the ldap_parse_result() function to parse the LDAPMessage structure to determine if the operation was successful.

The following example calls the asynchronous ldap_modify_ext() function to modify the entry for the user William Jensen in the directory.

#include <stdio.h>
#include "ldap.h"

#define MODIFY_DN "uid=wbjensen,ou=People,dc=example,dc=com"

LDAP      *ld;
LDAPMessage    *res;
LDAPMod      *mods[ 3 ];
LDAPControl    **serverctrls;
char      *matched_msg = NULL, *error_msg = NULL;
char      **referrals;
int        rc, parse_rc, msgid, finished = 0;

/* Timeout period for the ldap_result() function to wait for results. */
struct timeval  zerotime;
zerotime.tv_sec = zerotime.tv_usec = 0L;

/* Send the LDAP modify request. */
rc = ldap_modify_ext( ld, MODIFY_DN, mods, NULL, NULL, msgid );
if ( rc != LDAP_SUCCESS ) {
  fprintf( stderr, "ldap_modify_ext: %s\n", ldap_err2string( rc ) );
  ldap_unbind( ld );
  return( 1 );
}

/* Poll the server for the results of the modify operation. */
while ( !finished ) {
  rc = ldap_result( ld, msgid, 0, zerotime, res );
  switch ( rc ) {
  case -1:
    /* An error occurred. */
      rc = ldap_get_lderrno( ld, NULL, NULL );
      fprintf( stderr, "ldap_result: %s\n", ldap_err2string( rc ) );
      ldap_unbind( ld );
      return( 1 );
  case 0:
    /* The timeout period specified by zerotime was exceeded,
      so call ldap_result() again and continue polling. */
    break;
  default:
    /* The function has retrieved the results of the
      modify operation. */
    finished = 1;

    /* Parse the results received from the server. */
    parse_rc = ldap_parse_result( ld, res, rc, matched_msg,
      error_msg, referrals, serverctrls, 1 );
    if ( parse_rc != LDAP_SUCCESS ) {
      fprintf( stderr, "ldap_parse_result: %s\n",
        ldap_err2string( parse_rc ) );
      ldap_unbind( ld );
      return( 1 );
    }

    /* Check the results of the LDAP modify operation. */
    if ( rc != LDAP_SUCCESS ) {
      fprintf( stderr, "ldap_modify_ext: %s\n",
        ldap_err2string( rc ) );
      if ( error_msg != NULL  *error_msg != '\0' ) {
        fprintf( stderr, "%s\n", error_msg );
      }
      if ( matched_msg != NULL  *matched_msg != '\0' ) {
        fprintf( stderr,
        "Part of the DN that matches an existing entry: %s\n",
        matched_msg );
      }
    } else {
      printf( "%s modified successfully.\n", MODIFY_DN );
    }
  }
}
ldap_unbind( ld );

The following sample program calls the asynchronous ldap_modify_ext() function to modify a user entry in the directory. The program replaces the values of the mail attribute and adds a description attribute to the entry.

#include <stdio.h>
#include <time.h>
#include "ldap.h"
void do_other_work();
int global_counter = 0;
/* Change these as needed. */
#define HOSTNAME "localhost"
#define PORTNUMBER LDAP_PORT
#define BIND_DN "cn=Directory Manager"
#define BIND_PW "23skidoo"
#define MODIFY_DN "uid=wbjensen,ou=People,dc=example,dc=com"
int
main( int argc, char **argv )
{
  LDAP           *ld;
  LDAPMessage    *res;
  LDAPMod        mod0, mod1;
  LDAPMod        *mods[ 3 ];
  LDAPControl    **serverctrls;
  char           *matched_msg = NULL, *error_msg = NULL;
  char           **referrals;
  char           *vals0[ 2 ], *vals1[ 2 ];
  time_t      now;
  char      buf[ 128 ];
  int        rc, parse_rc, msgid, finished = 0;
  struct timeval  zerotime;
  zerotime.tv_sec = zerotime.tv_usec = 0L;
/* Get a handle to an LDAP connection. Use prldap_init() for IPv6. */
  if ( (ld = ldap_init( HOSTNAME, PORTNUMBER )) == NULL ) {
    perror( "ldap_init" );
    return( 1 );
  }
/* Bind to the server as the Directory Manager. */
  rc = ldap_simple_bind_s( ld, BIND_DN, BIND_PW );
  if ( rc != LDAP_SUCCESS ) {
    fprintf( stderr, "ldap_simple_bind_s: %s\n", ldap_err2string( rc ) );
    ldap_get_lderrno( ld, matched_msg, error_msg );
    if ( error_msg != NULL  *error_msg != '\0' ) {
      fprintf( stderr, "%s\n", error_msg );
    }
    if ( matched_msg != NULL  *matched_msg != '\0' ) {
      fprintf( stderr,
        "Part of the DN that matches an existing entry: %s\n",
        matched_msg );
    }
    ldap_unbind_s( ld );
    return( 1 );
  }
/* Construct the array of LDAPMod structures representing the changes
   that you want to make to attributes in the entry. */
/* Specify the first modification, which replaces all values of the
   mail attribute with the value "wbj@example.com". */
  mod0.mod_op = LDAP_MOD_REPLACE;
  mod0.mod_type = "mail";
  vals0[0] = "wbj@example.com";
  vals0[1] = NULL;
  mod0.mod_values = vals0;
/* Specify the second modification, which adds a value to the description
   attribute.  If this attribute does not yet exist, the attribute ia added
   to the entry. */
  mod1.mod_op = LDAP_MOD_ADD;
  mod1.mod_type = "description";
  time( now );
  sprintf( buf,
           "This entry was modified with the modattrs program on %s",
           ctime( now ));
/* Get rid of \n which ctime put on the end of the time string */
  if ( buf[ strlen( buf ) - 1 ] == '\n' ) {
    buf[ strlen( buf ) - 1 ] = '\0';
  }
  vals1[ 0 ] = buf;
  vals1[ 1 ] = NULL;
  mod1.mod_values = vals1;
  mods[ 0 ] = mod0;
  mods[ 1 ] = mod1;
  mods[ 2 ] = NULL;
/* Send the LDAP modify request. */
  rc = ldap_modify_ext( ld, MODIFY_DN, mods, NULL, NULL, msgid );
  if ( rc != LDAP_SUCCESS ) {
    fprintf( stderr, "ldap_modify_ext: %s\n", ldap_err2string( rc ) );
    ldap_unbind( ld );
    return( 1 );
  }
/* Poll the server for the results of the modify operation. */
  while ( !finished ) {
    rc = ldap_result( ld, msgid, 0, zerotime, res );
    switch ( rc ) {
    case -1:
      /* An error occurred. */
      rc = ldap_get_lderrno( ld, NULL, NULL );
      fprintf( stderr, "ldap_result: %s\n", ldap_err2string( rc ) );
      ldap_unbind( ld );
      return( 1 );
    case 0:
      /* The timeout period specified by zerotime was exceeded.
         This means that the server has still not yet sent the
         results of the modify operation back to your client.
         Break out of this switch statement, and continue calling
         ldap_result() to poll for results. */
      break;
    default:
      /* The function has retrieved the results of the modify
         operation from the server. */
      finished = 1;
      /* Parse the results received from the server. Note the last
         argument is a non-zero value, which indicates that the
         LDAPMessage structure will be freed when done.  (No need
         to call ldap_msgfree().) */
      parse_rc = ldap_parse_result( ld, res, rc, matched_msg,
                   error_msg, referrals, serverctrls, 1 );
      if ( parse_rc != LDAP_SUCCESS ) {
        fprintf( stderr,
                 "ldap_parse_result: %s\n",
                 ldap_err2string( parse_rc ) );
        ldap_unbind( ld );
        return( 1 );
      }
      /* Check the results of the LDAP add operation. */
      if ( rc != LDAP_SUCCESS ) {
        fprintf( stderr, "ldap_modify_ext: %s\n", ldap_err2string( rc ) );
        if ( error_msg != NULL  *error_msg != '\0' ) {
          fprintf( stderr, "%s\n", error_msg );
        }
        if ( matched_msg != NULL  *matched_msg != '\0' ) {
          fprintf( stderr,
            "Part of the DN that matches an existing entry: %s\n",
            matched_msg );
        }
      } else {
        printf( "%s modified successfully.\n"
          "Counted to %d while waiting for the modify operation.\n",
          MODIFY_DN, global_counter );
      }
    }
/* Do other work while waiting for the results of the modify operation. */
    if ( !finished ) {
      do_other_work();
    }
  }
  ldap_unbind( ld );
  return 0;
}

/*
 * Perform other work while polling for results.  This doesn't do anything
 * useful, but it could.
 */
void
do_other_work()
{
  global_counter++;
}

Deleting an Entry With LDAP C SDK

  • The synchronous ldap_delete_ext_s() function
  • The asynchronous ldap_delete_ext() function


Synchronous Delete Operation


If you want to wait for the results of the delete operation to complete before continuing, call the synchronous ldap_delete_ext_s() function. This function sends a delete request to the server. The function also blocks all other processes until the server sends the results of the operation back to your client. The ldap_delete_ext_s() function returns LDAP_SUCCESS if the operation completed successfully, or an error code if a problem occurred.

The following example calls the synchronous ldap_delete_ext_s function to remove the entry for user William Jensen from the directory.

#include <stdio.h>
#include "ldap.h"

#define DELETE_DN "uid=wjensen,ou=People,dc=example,dc=com"

LDAP      *ld;
char      *matched_msg = NULL, *error_msg = NULL;
int      rc;

/* Perform the delete operation. */
rc = ldap_delete_ext_s( ld, DELETE_DN, NULL, NULL );
if ( rc != LDAP_SUCCESS ) {
  fprintf( stderr, "ldap_delete_ext_s: %s\n", ldap_err2string( rc ) );
  ldap_get_lderrno( ld, matched_msg, error_msg );
  if ( error_msg != NULL  *error_msg != '\0' ) {
    fprintf( stderr, "%s\n", error_msg );
  }
  if ( matched_msg != NULL  *matched_msg != '\0' ) {
    fprintf( stderr,
      "Part of the DN that matches an existing entry: %s\n",
      matched_msg );
  }
} else {
  printf( "%s deleted successfully.\n", DELETE_DN );
}
ldap_unbind_s( ld );

The following sample program calls the synchronous ldap_delete_ext_s() function to delete a user entry from the directory.

#include <stdio.h>
#include "ldap.h"
/* Change these as needed. */
#define HOSTNAME "localhost"
#define PORTNUMBER LDAP_PORT
#define BIND_DN "cn=Directory Manager"
#define BIND_PW "23skidoo"
#define DELETE_DN "uid=wjensen,ou=People,dc=example,dc=com"
int
main( int argc, char **argv )
{
  LDAP      *ld;
  char      *matched_msg = NULL, *error_msg = NULL;
  int        rc;
/* Get a handle to an LDAP connection. Use prldap_init() for IPv6. */
  if ( (ld = ldap_init( HOSTNAME, PORTNUMBER )) == NULL ) {
    perror( "ldap_init" );
    return( 1 );
  }
/* Bind to the server as the Directory Manager. */
  rc = ldap_simple_bind_s( ld, BIND_DN, BIND_PW );
  if ( rc != LDAP_SUCCESS ) {
    fprintf( stderr, "ldap_simple_bind_s: %s\n", ldap_err2string( rc ) );
    ldap_get_lderrno( ld, matched_msg, error_msg );
    if ( error_msg != NULL  *error_msg != '\0' ) {
      fprintf( stderr, "%s\n", error_msg );
    }
    if ( matched_msg != NULL  *matched_msg != '\0' ) {
      fprintf( stderr,
        "Part of the DN that matches an existing entry: %s\n",
        matched_msg );
    }
    ldap_unbind_s( ld );
    return( 1 );
  }
/* Perform the delete operation. */
  rc = ldap_delete_ext_s( ld, DELETE_DN, NULL, NULL );
  if ( rc != LDAP_SUCCESS ) {
    fprintf( stderr, "ldap_delete_ext_s: %s\n", ldap_err2string( rc ) );
    ldap_get_lderrno( ld, matched_msg, error_msg );
    if ( error_msg != NULL  *error_msg != '\0' ) {
      fprintf( stderr, "%s\n", error_msg );
    }
    if ( matched_msg != NULL  *matched_msg != '\0' ) {
      fprintf( stderr,
        "Part of the DN that matches an existing entry: %s\n",
        matched_msg );
    }
  } else {
    printf( "%s deleted successfully.\n", DELETE_DN );
  }
  ldap_unbind_s( ld );
  return 0;
}

Asynchronous Delete Operation


If you want to perform other work in parallel while waiting for the entry to be deleted, call the asynchronous ldap_delete_ext() function. This function sends a delete request to the server and returns an LDAP_SUCCESS result code if the request was successfully sent, an LDAP result code if an error occurred.

The ldap_delete_ext() function passes back a message ID identifying the delete operation. To determine whether the server sent a response for this operation to your client, call the ldap_result() function and pass in this message ID. The ldap_result() function uses the message ID to determine if the server sent the results of the delete operation. The ldap_result() function passes back the results in an LDAPMessage structure. You can call the ldap_parse_result() function to parse the LDAPMessage structure to determine if the operation was successful.

The following example calls the asynchronous ldap_delete_ext() function to remove the user William Jensen from the directory.

#include <stdio.h>
#include "ldap.h"

#define DELETE_DN "uid=wjensen,ou=People,dc=example,dc=com"

LDAP      *ld;
LDAPMessage    *res;
LDAPControl    **serverctrls;
char      *matched_msg = NULL, *error_msg = NULL;
char      **referrals;
int        rc, parse_rc, msgid, finished = 0;

/* Timeout period for the ldap_result() function to wait for results. */
struct timeval  zerotime;
zerotime.tv_sec = zerotime.tv_usec = 0L;

/* Send the LDAP delete request. */
rc = ldap_delete_ext( ld, DELETE_DN, NULL, NULL, msgid );
if ( rc != LDAP_SUCCESS ) {
  fprintf( stderr, "ldap_delete_ext: %s\n", ldap_err2string( rc ) );
  ldap_unbind( ld );
  return( 1 );
}

/* Poll the server for the results of the delete operation. */
while ( !finished ) {
  rc = ldap_result( ld, msgid, 0, zerotime, res );
  switch ( rc ) {
  case -1:
    /* An error occurred. */
    rc = ldap_get_lderrno( ld, NULL, NULL );
    fprintf( stderr, "ldap_result: %s\n", ldap_err2string( rc ) );
    ldap_unbind( ld );
    return( 1 );
  case 0:
    /* The timeout period specified by zerotime was exceeded,
      so call ldap_result() again and continue polling. */
      break;
  default:
    /* The function has retrieved the results of the
      delete operation. */
      finished = 1;

    /* Parse the results received from the server. */
    parse_rc = ldap_parse_result( ld, res, rc, matched_msg,
      error_msg, referrals, serverctrls, 1 );
    if ( parse_rc != LDAP_SUCCESS ) {
      fprintf( stderr, "ldap_parse_result: %s\n",
        ldap_err2string( parse_rc ) );
      ldap_unbind( ld );
      return( 1 );
    }
    /* Check the results of the LDAP delete operation. */
    if ( rc != LDAP_SUCCESS ) {
      fprintf( stderr, "ldap_delete_ext: %s\n",
        ldap_err2string( rc ) );
      if ( error_msg != NULL  *error_msg != '\0' ) {
        fprintf( stderr, "%s\n", error_msg );
      }
      if ( matched_msg != NULL  *matched_msg != '\0' ) {
        fprintf( stderr,
          "Part of the DN that matches an existing entry: %s\n",
          matched_msg );
      }
    } else {
      printf( "%s deleted successfully.\n", DELETE_DN );
    }
  }
}
ldap_unbind( ld );

The following sample program calls the asynchronous ldap_delete_ext() function to delete a user entry from the directory.

#include <stdio.h>
#include "ldap.h"
void do_other_work();
int global_counter = 0;
/* Change these as needed. */
#define HOSTNAME "localhost"
#define PORTNUMBER LDAP_PORT
#define BIND_DN "cn=Directory Manager"
#define BIND_PW "23skidoo"
#define DELETE_DN "uid=wjensen,ou=People,dc=example,dc=com"
int
main( int argc, char **argv )
{
  LDAP      *ld;
  LDAPMessage    *res;
  LDAPControl    **serverctrls;
  char      *matched_msg = NULL, *error_msg = NULL;
  char      **referrals;
  int        rc, parse_rc, msgid, finished = 0;
  struct timeval  zerotime;
  zerotime.tv_sec = zerotime.tv_usec = 0L;
/* Get a handle to an LDAP connection. Use prldap_init() for IPv6. */
  if ( (ld = ldap_init( HOSTNAME, PORTNUMBER )) == NULL ) {
    perror( "ldap_init" );
    return( 1 );
  }
/* Bind to the server as the Directory Manager. */
  rc = ldap_simple_bind_s( ld, BIND_DN, BIND_PW );
  if ( rc != LDAP_SUCCESS ) {
    fprintf( stderr, "ldap_simple_bind_s: %s\n", ldap_err2string( rc ) );
    ldap_get_lderrno( ld, matched_msg, error_msg );
    if ( error_msg != NULL  *error_msg != '\0' ) {
      fprintf( stderr, "%s\n", error_msg );
    }
    if ( matched_msg != NULL  *matched_msg != '\0' ) {
      fprintf( stderr,
        "Part of the DN that matches an existing entry: %s\n",
        matched_msg );
    }
    ldap_unbind_s( ld );
    return( 1 );
  }
/* Send the LDAP delete request. */
  rc = ldap_delete_ext( ld, DELETE_DN, NULL, NULL, msgid );
  if ( rc != LDAP_SUCCESS ) {
    fprintf( stderr, "ldap_delete_ext: %s\n", ldap_err2string( rc ) );
    ldap_unbind( ld );
    return( 1 );
  }
/* Poll the server for the results of the delete operation. */
  while ( !finished ) {
    rc = ldap_result( ld, msgid, 0, zerotime, res );
    switch ( rc ) {
    case -1:
      /* An error occurred. */
      rc = ldap_get_lderrno( ld, NULL, NULL );
      fprintf( stderr, "ldap_result: %s\n", ldap_err2string( rc ) );
      ldap_unbind( ld );
      return( 1 );
    case 0:
      /* The timeout period specified by zerotime was exceeded.
         This means that the server has still not yet sent the
         results of the delete operation back to your client.
         Break out of this switch statement, and continue calling
         ldap_result() to poll for results. */
      break;
    default:
  /* The function has retrieved the results of the delete operation
     from the server. */
      finished = 1;
      /* Parse the results received from the server. Note the last
         argument is a non-zero value, which indicates that the
         LDAPMessage structure will be freed when done.  (No need
         to call ldap_msgfree().) */
      parse_rc = ldap_parse_result( ld, res, rc, matched_msg,
                   error_msg, referrals, serverctrls, 1 );
      if ( parse_rc != LDAP_SUCCESS ) {
        fprintf( stderr,
                 "ldap_parse_result: %s\n",
                 ldap_err2string( parse_rc ) );
        ldap_unbind( ld );
        return( 1 );
      }
      /* Check the results of the LDAP delete operation. */
      if ( rc != LDAP_SUCCESS ) {
        fprintf( stderr, "ldap_delete_ext: %s\n", ldap_err2string( rc ) );
        if ( error_msg != NULL  *error_msg != '\0' ) {
          fprintf( stderr, "%s\n", error_msg );
        }
        if ( matched_msg != NULL  *matched_msg != '\0' ) {
        fprintf( stderr,
          "Part of the DN that matches an existing entry: %s\n",
          matched_msg );
        }
      } else {
        printf( "%s deleted successfully.\n"
          "Counted to %d while waiting for the delete operation.\n",
          DELETE_DN, global_counter );
      }
    }
    /* Do other work while waiting for the results of the
       delete operation. */
    if ( !finished ) {
      do_other_work();
    }
  }
  ldap_unbind( ld );
  return 0;
}
/*
 * Perform other work while polling for results.  This
 * doesn't do anything useful, but it could.
 */
void
do_other_work()
{
    global_counter++;
}

Changing the DN of an Entry With LDAP C SDK

  • The synchronous ldap_rename_s() function
  • The asynchronous ldap_rename() function

For both functions, you can choose to delete the attribute that represents the old relative distinguished name (RDN). You can also change the location of the entry in the directory tree.


Synchronous Renaming Operation


If you want to wait for the results of the modify DN operation to complete before continuing, call the synchronous ldap_rename_s() function. This function sends a modify DN request to the server. The function also blocks other work until the server sends the results of the operation back to your client. The ldap_rename_s() function returns LDAP_SUCCESS if the operation completed successfully, or an error code if a problem occurred.

The following calls the synchronous ldap_rename_s() function to change the RDN of the entry for the user William Jensen in the directory.

#include <stdio.h>
#include "ldap.h"

#define OLD_DN "uid=wbjensen,ou=People,dc=example,dc=com"
#define NEW_RDN "uid=wjensen"

LDAP      *ld;
char      *matched_msg = NULL, *error_msg = NULL;
int        rc;

/* Perform the modify DN operation. */
rc = ldap_rename_s( ld, OLD_DN, NEW_RDN, NULL, 1, NULL, NULL );
if ( rc != LDAP_SUCCESS ) {
  fprintf( stderr, "ldap_rename_s: %s\n", ldap_err2string( rc ) );
  ldap_get_lderrno( ld, matched_msg, error_msg );
  if ( error_msg != NULL  *error_msg != '\0' ) {
    fprintf( stderr, "%s\n", error_msg );
  }
  if ( matched_msg != NULL  *matched_msg != '\0' ) {
    fprintf( stderr,
      "Part of the DN that matches an existing entry: %s\n",
      matched_msg );
  }
} else {
  printf( "%s renamed successfully.\n", OLD_DN );
}
ldap_unbind_s( ld );

Asynchronous Renaming Operation


If you want to perform other work in parallel while waiting for the entry to be renamed, call the asynchronous ldap_rename() function. This function sends a modify DN request to the server and returns an LDAP_SUCCESS result code if the request was successfully sent, or an LDAP result code if an error occurred.

The ldap_rename() function passes back a message ID identifying the modify DN operation. To determine whether the server sent a response for this operation to your client, call the ldap_result() function and pass in this message ID. The ldap_result() function uses the message ID to determine if the server sent the results of the modify DN operation. The ldap_result() function passes back the results in an LDAPMessage structure. You can call the ldap_parse_result() function to parse the LDAPMessage structure to determine if the operation was successful.

The following example calls the asynchronous ldap_rename() function to change the RDN of the user William Jensen in the directory.

#include <stdio.h>
#include "ldap.h"

#define OLD_DN "uid=wbjensen,ou=People,dc=example,dc=com"
#define NEW_RDN "uid=wjensen"

LDAP      *ld;
LDAPMessage    *res;
LDAPControl    **serverctrls;
char      *matched_msg = NULL, *error_msg = NULL;
char      **referrals;
int        rc, parse_rc, msgid, finished = 0;

/* Timeout period for the ldap_result() function to wait
   for results. */
struct timeval  zerotime;
zerotime.tv_sec = zerotime.tv_usec = 0L;

/* Send the LDAP modify DN request. */
rc = ldap_rename( ld, OLD_DN, NEW_RDN, NULL, 1, NULL, NULL, msgid );
if ( rc != LDAP_SUCCESS ) {
  fprintf( stderr, "ldap_rename: %s\n", ldap_err2string( rc ) );
  ldap_unbind( ld );
  return( 1 );
}

/* Poll the server for the results of the modify DN operation. */
while ( !finished ) {
  rc = ldap_result( ld, msgid, 0, zerotime, res );
  switch ( rc ) {
  case -1:
    /* An error occurred. */
    rc = ldap_get_lderrno( ld, NULL, NULL );
    fprintf( stderr, "ldap_result: %s\n", ldap_err2string( rc ) );
    ldap_unbind( ld );
    return( 1 );
  case 0:
    /* The timeout period specified by zerotime was exceeded,
      so call ldap_result() again and continue polling. */
    break;
  default:
    /* The function has retrieved the results of the
      modify DN operation. */
    finished = 1;

    /* Parse the results received from the server. */
    parse_rc = ldap_parse_result( ld, res, rc, matched_msg,
      error_msg, referrals, serverctrls, 1 );
    if ( parse_rc != LDAP_SUCCESS ) {
      fprintf( stderr, "ldap_parse_result: %s\n",
        ldap_err2string( parse_rc ) );
      ldap_unbind( ld );
      return( 1 );
    }

    /* Check the results of the LDAP modify DN operation. */
    if ( rc != LDAP_SUCCESS ) {
      fprintf( stderr, "ldap_rename: %s\n", ldap_err2string( rc ) );
      if ( error_msg != NULL  *error_msg != '\0' ) {
        fprintf( stderr, "%s\n", error_msg );
      }
      if ( matched_msg != NULL  *matched_msg != '\0' ) {
        fprintf( stderr,
          "Part of the DN that matches an existing entry: %s\n",
          matched_msg );
      }
    } else {
      printf( "%s renamed successfully.\n", OLD_DN );
    }
  }
}
ldap_unbind( ld );

Deleting the Attribute From the Old RDN


Both ldap_rename and ldap_rename_s() have a deleteoldrdn parameter that allows you to remove the old RDN from the entry. For example, suppose an entry has the following values for the cn attribute:

cn: Barbara Jensen
cn: Babs Jensen

Then the following function adds the second name and removes the first:

ldap_modrdn2( "cn=Barbara Jensen", "cn=Barbie Jensen", 1 );

The function adds Barbie Jensen to the list of values. The function removes the Barbara Jensen value. The resulting entry has the following values:

cn: Barbie Jensen
cn: Babs Jensen

Suppose 0 is passed for the deleteoldrdn parameter instead of 1:

ldap_modrdn2( "cn=Barbara Jensen", "cn=Barbie Jensen", 0 );

The Barbara Jensen value is not removed from the entry. The resulting entry has the following values:

cn: Barbie Jensen
cn: Babs Jensen
cn: Barbara Jensen

Changing the Location of the Entry


Both ldap_rename() and ldap_rename_s() have a newparent parameter that allows you to specify a new location for the entry in the directory tree. For example, if you pass ou=Contractors,dc=example,dc=com as the newparent parameter when renaming the entry uid=bjensen,ou=People,dc=example,dc=com, the entry is moved under ou=Contractors,dc=example,dc=com. The new DN for the entry is uid=bjensen,ou=Contractors,dc=example,dc=com.

Note: Some LDAP servers do not support this feature. When you specify this argument, a server might return the LDAP result code LDAP_UNWILLING_TO_PERFORM, with the error message Server does not support moving of entries.


Synchronous Relocation of an Entry


The following example calls the synchronous ldap_rename_s() function to change the RDN of a user entry in the directory.

#include <stdio.h>
#include "ldap.h"
/* Change these as needed. */
#define HOSTNAME "localhost"
#define PORTNUMBER LDAP_PORT
#define BIND_DN "cn=Directory Manager"
#define BIND_PW "23skidoo"
#define OLD_DN "uid=wbjensen,ou=People,dc=example,dc=com"
#define NEW_RDN "uid=wjensen"
int
main( int argc, char **argv )
{
  LDAP      *ld;
  char      *matched_msg = NULL, *error_msg = NULL;
  int        rc;
/* Get a handle to an LDAP connection. Use prldap_init() for IPv6. */
  if ( (ld = ldap_init( HOSTNAME, PORTNUMBER )) == NULL ) {
    perror( "ldap_init" );
    return( 1 );
  }
/* Bind to the server as the Directory Manager. */
  rc = ldap_simple_bind_s( ld, BIND_DN, BIND_PW );
  if ( rc != LDAP_SUCCESS ) {
    fprintf( stderr, "ldap_simple_bind_s: %s\n", ldap_err2string( rc ) );
    ldap_get_lderrno( ld, matched_msg, error_msg );
    if ( error_msg != NULL  *error_msg != '\0' ) {
      fprintf( stderr, "%s\n", error_msg );
    }
    if ( matched_msg != NULL  *matched_msg != '\0' ) {
      fprintf( stderr,
        "Part of the DN that matches an existing entry: %s\n",
        matched_msg );
    }
    ldap_unbind_s( ld );
    return( 1 );
  }
/* Perform the modify DN operation. */
  rc = ldap_rename_s( ld, OLD_DN, NEW_RDN, NULL, 1, NULL, NULL );
  if ( rc != LDAP_SUCCESS ) {
    fprintf( stderr, "ldap_rename_s: %s\n", ldap_err2string( rc ) );
    ldap_get_lderrno( ld, matched_msg, error_msg );
    if ( error_msg != NULL  *error_msg != '\0' ) {
      fprintf( stderr, "%s\n", error_msg );
    }
    if ( matched_msg != NULL  *matched_msg != '\0' ) {
      fprintf( stderr,
        "Part of the DN that matches an existing entry: %s\n",
        matched_msg );
    }
  } else {
    printf( "%s renamed successfully.\n", OLD_DN );
  }
  ldap_unbind_s( ld );
  return 0;
}

Asynchronous Relocation of an Entry


The following example calls the asynchronous ldap_rename() function to change the RDN of a user entry in the directory.

#include <stdio.h>
#include "ldap.h"
void do_other_work();
int global_counter = 0;
/* Change these as needed. */
#define HOSTNAME "localhost"
#define PORTNUMBER LDAP_PORT
#define BIND_DN "cn=Directory Manager"
#define BIND_PW "dougy4444"
#define OLD_DN "uid=wbjensen,ou=People,dc=example,dc=com"
#define NEW_RDN "uid=wjensen"
int
main( int argc, char **argv )
{
  LDAP      *ld;
  LDAPMessage    *res;
  LDAPControl    **serverctrls;
  char      *matched_msg = NULL, *error_msg = NULL;
  char      **referrals;
  int        rc, parse_rc, msgid, finished = 0;
  struct timeval  zerotime;
  zerotime.tv_sec = zerotime.tv_usec = 0L;
/* Get a handle to an LDAP connection. Use prldap_init() for IPv6. */
  if ( (ld = ldap_init( HOSTNAME, PORTNUMBER )) == NULL ) {
    perror( "ldap_init" );
    return( 1 );
  }
/* Bind to the server as the Directory Manager. */
  rc = ldap_simple_bind_s( ld, BIND_DN, BIND_PW );
  if ( rc != LDAP_SUCCESS ) {
    fprintf( stderr, "ldap_simple_bind_s: %s\n", ldap_err2string( rc ) );
    ldap_get_lderrno( ld, matched_msg, error_msg );
    if ( error_msg != NULL  *error_msg != '\0' ) {
      fprintf( stderr, "%s\n", error_msg );
    }
    if ( matched_msg != NULL  *matched_msg != '\0' ) {
      fprintf( stderr,
        "Part of the DN that matches an existing entry: %s\n",
        matched_msg );
    }
    ldap_unbind_s( ld );
    return( 1 );
  }
/* Send the LDAP modify DN request. */
  rc = ldap_rename( ld, OLD_DN, NEW_RDN, NULL, 1, NULL, NULL, msgid );
  if ( rc != LDAP_SUCCESS ) {
    fprintf( stderr, "ldap_rename: %s\n", ldap_err2string( rc ) );
    ldap_unbind( ld );
    return( 1 );
  }
/* Poll the server for the results of the modify DN operation. */
  while ( !finished ) {
    rc = ldap_result( ld, msgid, 0, zerotime, res );
    switch ( rc ) {
    case -1:
      /* An error occurred. */
      rc = ldap_get_lderrno( ld, NULL, NULL );
      fprintf( stderr, "ldap_result: %s\n", ldap_err2string( rc ) );
      ldap_unbind( ld );
      return( 1 );
    case 0:
      /* The timeout period specified by zerotime was exceeded.
         This means that the server has still not yet sent the
         results of the modify DN operation back to your client.
         Break out of this switch statement, and continue calling
         ldap_result() to poll for results. */
      break;
    default:
  /* The function has retrieved the results of the modify DN operation
         from the server. */
      finished = 1;
      /* Parse the results received from the server. Note the last
         argument is a non-zero value, which indicates that the
         LDAPMessage structure will be freed when done.  (No need
         to call ldap_msgfree().) */
      parse_rc = ldap_parse_result( ld, res, rc, matched_msg,
        error_msg, referrals, serverctrls, 1 );
      if ( parse_rc != LDAP_SUCCESS ) {
        fprintf( stderr,
                 "ldap_parse_result: %s\n",
                 ldap_err2string( parse_rc ) );
        ldap_unbind( ld );
        return( 1 );
      }
      /* Check the results of the LDAP modify DN operation. */
      if ( rc != LDAP_SUCCESS ) {
        fprintf( stderr, "ldap_rename: %s\n", ldap_err2string( rc ) );
        if ( error_msg != NULL  *error_msg != '\0' ) {
          fprintf( stderr, "%s\n", error_msg );
        }
        if ( matched_msg != NULL  *matched_msg != '\0' ) {
          fprintf( stderr,
            "Part of the DN that matches an existing entry: %s\n",
            matched_msg );
        }
      } else {
        printf( "%s renamed successfully.\n"
          "Counted to %d while waiting for the modify DN operation.\n",
          OLD_DN, global_counter );
      }
    }
    /* Do other work while waiting for the results of the
       modify DN operation. */
    if ( !finished ) {
      do_other_work();
    }
  }
  ldap_unbind( ld );
  return 0;
}
/*
 * Perform other work while polling for results.  This doesn't do
 * anything useful, but it could.
 */
void
do_other_work()
{
    global_counter++;
}