Sun logo      Previous      Contents      Index      Next     

Sun Java System LDAP SDK for C Programming Guide

Chapter 7
Adding, Modifying and Deleting Entries

Sun™ Java System LDAP SDK for C contains functions to add, modify, delete, and rename entries in the directory. This chapter explains these functions and provides examples for calling them to perform their respective operations. It includes the following sections:


Specifying Entry Information

In order to add or modify an entry in the directory, you need to specify information about the entry’s attributes. In most cases, you will need to specify the following:

To specify this information, you use an LDAPMod structure as illustrated in Code Example 7-1.

Code Example 7-1  Defining a LDAPMod Structure

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;

Table 7-1 details the fields in the LDAPMod data structure.

Table 7-1  LDAPMod Field Descriptions 

Field

Description

mod_op

The operation to be performed on the attribute and the type of data specified as the attribute values. This field can have one of the following values:

  • LDAP_MOD_ADD adds a value to the attribute.
  • LDAP_MOD_DELETE removes the value from the attribute.
  • LDAP_MOD_REPLACE replaces all existing values of the attribute.

In addition, if you are specifying binary values in the mod_bvalues field, you should use the bitwise OR operator ( | ) to combine LDAP_MOD_BVALUES with the operation type. For example:

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). See "Adding an Entry" for details.

mod_type

Attribute type that you want to add, delete, or replace the values of (for example, 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.

Note the following caveats regarding entry modifications and the parameters detailed in Table 7-1:

If you’ve allocated memory for the structures yourself, you should free the structures when you’re finished by calling the ldap_mods_free() function.


Adding an Entry

This is the procedure to add a new entry to the directory.

  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 ldap_add_ext() or ldap_add_ext_s(), 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 you’ve allocated.

Specifying Values for Attributes

There are three ways to specify a value for an attribute. You can specify a single value, multiple values, or 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. Code Example 7-2 sets up the structure for the sn attribute.

Code Example 7-2  Setting Up an Attribute Structure 

#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. Code Example 7-3 specifies two values for the cn attribute.

Code Example 7-3  Specifying Multiple Values in an 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 like that in Code Example 7-4.

Code Example 7-4  Berval Structure

struct berval {

unsigned long bv_len;

char *bv_val;

}

Table 7-2 lists the berval structure field descriptions.

Table 7-2  berval Field Descriptions

Field

Description

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 need to:

  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 can just set the mod_op field to LDAP_MOD_BVALUES, since the mod_op field is 0 in this case.)

For example, suppose the file my_photo.jpg contains a JPEG photograph of Barbara Jensen. Code Example 7-5 sets the jpegPhoto attribute to the JPEG data of the photograph.

Code Example 7-5  Adding a Value to an Attribute 

#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, you need to construct an array of these structures. You will then pass a pointer to this array as a parameter to the function for creating a new entry.


Note

Make sure that you create LDAPMod structures for all required attributes in the new entry. If using Sun Java System Directory Server, see the chapters on required object classes and attributes in the Sun ONE Directory Server Administration Guide (http://docs.sun.com/doc/816-6698-10). For information on which attributes are required in other LDAP servers, see your server’s documentation.


Code Example 7-6 creates an array of LDAPMod structures.

Code Example 7-6  Adding Array of Structures to an Attribute 

#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

To add the entry to the directory, call one of the following:

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


Note

See the documentation on the ldap_add_ext_s() function for a list of the possible result codes.


Code Example 7-7 uses the synchronous ldap_add_ext_s() function to add the user William Jensen to the directory.

Code Example 7-7  Synchronous Add Operation 

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

}

...

Code Example 7-8 is a sample program that calls the synchronous ldap_add_ext_s() function to add a new user to the directory.

Code Example 7-8  Sample Synchronous Add Entry Program 

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

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


Note

See the documentation on the ldap_add_ext() function for a list of the possible result codes.


Code Example 7-9 calls ldap_add_ext() to add the user William Jensen to the directory.

Code Example 7-9  Asynchronous Add Operation 

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

}

}

}

...

Code Example 7-10 is a sample program that calls the asynchronous ldap_add_ext() function to add a new user to the directory.

Code Example 7-10  Sample Asynchronous Add Program 

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

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

This is the procedure to modify an entry.

  1. Use the LDAPMod structure to specify a change to an attribute.
  2. Create an array of LDAPMod structures representing the changes that need to be made.
  3. Call the ldap_modify_ext() or ldap_modify_ext_s(), 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 you’ve allocated.

Types of Modifications

There are different types of modifications that can be performed on an entry. The following sections explain them.

Replacing the Values of an Attribute

To replace all existing values of an attribute, create an LDAPMod structure with the following:

If you want to specify binary data as berval structures (as opposed to string values), you need to do the following:

Also take note of the following two caveats:

  1. If you specify an attribute that does not exist in the entry, the attribute will be added to the entry.
  2. If you 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 contains LDAP_MOD_BVALUES), the attribute will be removed from the entry.

Code Example 7-11 specifies a change that replaces the values of the telephoneNumber attribute.

Code Example 7-11  Modifying an Attribute Value 

#include "ldap.h"

LDAPMod attribute1;

char *telephoneNumber_values[] = { "+1 650 555 1967", NULL };

attribute1.mod_type = "telephoneNumber";

attribute1.mod_op = LDAP_MOD_REPLACE;

attribute1.mod_values = telephoneNumber_values;

Removing Values from an Attribute

To remove values from an attribute, create an LDAPMod structure with the following:

If you want to specify binary data as berval structures (as opposed to string values), you need to do the following:

Also take note of the following two caveats:

  1. If you remove all values from the attribute, the attribute will be removed from the entry.
  2. If you 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 contains LDAP_MOD_BVALUES), the attribute will be removed from the entry.

Code Example 7-12 specifies the removal of one of the values of the facsimileTelephoneNumber attribute in the entry.

Code Example 7-12  Removing an Attribute Value 

#include "ldap.h"

LDAPMod attribute2;

char *fax_values[] = { "+1 650 555 1967", NULL };

attribute2.mod_type = "facsimileTelephoneNumber";

attribute2.mod_op = LDAP_MOD_DELETE;

attribute2.mod_values = fax_values;

...

Adding Values to an Attribute

To add values to an attribute to an entry, create an LDAPMod structure with the following:

If the attribute contains binary data (as opposed to string values), you need to do the following:

Code Example 7-13 adds values to the audio attribute of an entry.

Code Example 7-13  Adding Values to an Attribute 

#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

You can remove an attribute from an entry in either of the following ways:

Adding an Attribute

If you add or replace values in an attribute that does not yet exist in the entry, the attribute will be 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 will pass a pointer to this array as a parameter to the function for modifying the entry.) Code Example 7-14 creates an array of LDAPMod structures.

Code Example 7-14  Assembling 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 the Entry in the Directory

To modify the entry in the directory, call one of the following:

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. This function sends a modify request to the server and blocks all work until the server sends the results of the operation back to your client. It returns LDAP_SUCCESS if the operation completed successfully or an error code if a problem occurred.


Note

See the documentation on the ldap_modify_ext_s() function for a list of the possible result codes.


Code Example 7-15 uses the synchronous ldap_modify_ext_s() function to modify the entry for the user William Jensen in the directory.

Code Example 7-15  Synchronous Modify Operation 

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

...

Code Example 7-16 is a sample program that calls the synchronous ldap_modify_ext_s() function to modify a user’s entry in the directory. The program replaces the values of the mail attribute and adds a description attribute to the entry.

Code Example 7-16  Sample Synchronous Modify Program 

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

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


Note

See the documentation on the ldap_modify_ext() function for a list of the possible result codes.


Code Example 7-17 calls ldap_modify_ext() to modify the entry for the user William Jensen in the directory.

Code Example 7-17  Asynchronous Modify Operation 

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

...

Code Example 7-18 is a sample program that calls the asynchronous ldap_modify_ext() function to modify a user’s entry in the directory. The program replaces the values of the mail attribute and adds a description attribute to the entry.

Code Example 7-18  Sample Asynchronous Modify Program 

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

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

To remove an entry from the directory, call one of the following:

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


Note

See the documentation on the ldap_delete_ext_s() function for a list of the possible result codes.


Code Example 7-19 uses the synchronous ldap_delete_ext_s() function to remove the entry for user William Jensen from the directory.

Code Example 7-19  Synchronous Delete Operation 

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

...

Code Example 7-20 is a sample program that calls the synchronous ldap_delete_ext_s() function to delete a user’s entry from the directory.

Code Example 7-20  Sample Synchronous Delete Program 

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

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 (or 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 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.


Note

See the documentation on the ldap_delete_ext() function for a list of the possible result codes.


Code Example 7-21 calls ldap_delete_ext() to remove the user William Jensen from the directory.

Code Example 7-21  Asynchronous Delete Operation 

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

...

Code Example 7-22 is a sample program that calls the asynchronous ldap_delete_ext() function to delete a user’s entry from the directory.

Code Example 7-22  Sample Asynchronous Delete Program 

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

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

To change the distinguished name (DN) of an entry, call one of the following:

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


Note

See the documentation on the ldap_rename_s() function for a list of the possible result codes.


Code Example 7-23 uses the synchronous ldap_rename_s() function to change the RDN of the entry for the user William Jensen in the directory.

Code Example 7-23  Synchronous Renaming Operation 

#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. ldap_result() uses the message ID to determine if the server sent the results of the modify DN operation. The 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.


Note

See the documentation on the ldap_rename() function for a list of the possible result codes.


Code Example 7-24 calls ldap_rename() to change the RDN of the user William Jensen in the directory.

Code Example 7-24  Asynchronous Renaming Operation 

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

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

Is a function call that adds Barbie Jensen to this list of values and removes the Barbara Jensen value. The resulting entry has the following values:

cn: Barbie Jensen

cn: Babs Jensen

If a 0 is passed for the deleteoldrdn parameter (instead of a 1):

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

The Barbara Jensen value is not removed from the entry and 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 and the new DN for the entry is uid=bjensen,ou=Contractors,dc=example,dc=com.


Caution

Not all LDAP servers support this feature. You might specify this argument and receive the LDAP result code LDAP_UNWILLING_TO_PERFORM with the error message "Server does not support moving of entries.”


Synchronous Relocation of an Entry

Code Example 7-25 calls the synchronous ldap_rename_s() function to change the RDN of a user’s entry in the directory.

Code Example 7-25  Synchronous Relocating of an Entry 

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

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

Code Example 7-26 calls the asynchronous ldap_rename() function to change the RDN of a user’s entry in the directory.

Code Example 7-26  Asynchronous Relocating of an Entry 

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

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++;

}



Previous      Contents      Index      Next     


Copyright 2004 Sun Microsystems, Inc. All rights reserved.