Mozilla LDAP C SDK Programmer's Guide
Chapter 8 - Adding, Updating, and Deleting Entries
This chapter explains how to use the API functions to add, modify, delete, and rename entries in the directory. The chapter also provides examples of calling synchronous and asynchronous functions to perform these operations.
The chapter includes the following sections:
- Specifying a New or Modified Attribute
- Adding a New Entry
- Modifying an Entry
- Deleting an Entry
- Changing the DN of an Entry
Specifying a New or Modified Attribute
In order to add or modify an entry in the directory, you need to specify information about the entry's attributes:
- If you are adding an entry, you must specify the attributes in the new entry.
- If you are modifying an entry, you must specify the attributes and values that you are adding, replacing, or removing.
In most of the cases above, you need to specify the following attribute information:
- The operation that you are performing, if you are modifying an existing entry (in other words, adding, modifying, or deleting the attribute in the existing entry).
-
The type of attribute that you are working with (for example, the
snattribute or thetelephoneNumberattribute). - The values that you are adding or replacing in the attribute
To specify this information, you use an
LDAPMod structure.
Code Example 8-1 - Adding or modifying an attribute
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 table details the fields in the LDAPMod
data structure:
Table 8-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:
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
Note that 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 a New Entry" for details.
|
mod_type |
The attribute type that you want to add, delete, or replace the
values of (for example, "sn" or
"telephoneNumber").
|
mod_values |
A pointer to a NULL-terminated array of string
values for the attribute.
|
mod_bvalues |
A pointer to a NULL-terminated array of
berval structures for the
attribute.
|
Note the following:
-
If you specify
LDAP_MOD_DELETEin themod_opfield and you remove all values in an attribute, the attribute is removed from the entry. -
If you specify
LDAP_MOD_DELETEin themod_opfield andNULLin themod_valuesfield, the attribute is removed from the entry. -
If you specify
LDAP_MOD_REPLACEin themod_opfield andNULLin themod_valuesfield, the attribute is removed from the entry. -
If you specify
LDAP_MOD_REPLACEin themod_opfield and the attribute does not exist in the entry, the attribute is added to the entry. -
If you specify
LDAP_MOD_ADDin themod_opfield and the attribute does not exist in the entry, the attribute is added to the entry.
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.
For information on how to set up
LDAPMod structures to
add and modify entries in the directory, see the sections
"Specifying the Attributes" and
"Specifying the Changes."
Adding a New Entry
To add an entry to the directory:
-
Create an array of
LDAPModstructures to represent the attributes in the entry. Use theLDAPModstructure to specify the name and values of each attribute. -
Call the
ldap_add_ext()orldap_add_ext_s(), passing in the array ofLDAPModstructures and a distinguished name for the entry.
After you are done, call the
ldap_mods_free()
function to free any
LDAPMod structures
you've allocated.
Specifying the Attributes
This section describes the process of specifying the attributes and values of the new entry in the following sections:
- Specifying a Single Value in an Attribute
- Specifying Multiple Values in an Attribute
- Specifying Binary Data as the Values of an Attribute
- Specifying the Attributes in the Entry
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.
(See the section "Specifying
a New or Modified Attribute" for a brief overview of this structure.)
The following section of code sets up the structure for the
sn attribute:
Code Example 8-2 - Setting up an attribute structure
...
LDAPMod attribute1;
char *sn_values[] = { "Jensen", NULL };
...
attribute1.mod_op = 0;
attribute1.mod_type = "sn";
attribute1.mod_values = sn_values;
...
Note that 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:
Code Example 8-3 - Specifying multiple values in an attribute
...
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 Values of an Attribute
If the attribute contains binary data (rather than string values),
specify the data in a
berval structure:
struct berval {
unsigned long bv_len;
char *bv_val;
}
Table 8-2 - berval field descriptions
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 do the following:
-
Add the
bervalstructures to themod_bvaluesfield in theLDAPModstructure. -
Use the bitwise OR operator ( | ) to combine the value of the
mod_opfield withLDAP_MOD_BVALUES. (When adding a new entry, you can just set themod_opfield toLDAP_MOD_BVALUES, since themod_opfield 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.
Code Example 8-4 - 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 the Attributes in the Entry
After specifying the values of attributes 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 LDAP API function for
creating a new entry.)
Note:Make sure that you created
LDAPMod structures for
all required attributes in the new entry. For information on which
attributes are required, see the documentation for your LDAP server.
The following section of code creates an array of
LDAPMod structures:
Code Example 8-5 - Adding an array of structures to an attribute
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 functions:
-
The synchronous
ldap_add_ext_s()function (see"Performing a Synchronous Add Operation"). -
The asynchronous
ldap_add_ext()function (see"Performing an Asynchronous Add Operation").
(For more information about the difference between synchronous and asynchronous functions, see "Calling Synchronous and Asynchronous Functions.")
If you've allocated
LDAPMod structures
yourself, you should free the structures when you are done. Call the
ldap_mods_free()
function to free
LDAPMod structures.
Note:Before you add an entry, you should make sure that you've defined all required attributes for the entry type. For a listing of the required attributes for the different types of entries, see the documentation for your LDAP server.
Performing a 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 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. See the documentation on the
ldap_add_ext_s()
function for a list of the possible result codes.
The following section of code uses the synchronous
ldap_add_ext_s() function to add the user William
Jensen to the directory.
Code Example 8-6 - Synchronously adding an entry to the directory database
#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 );
}
...
Performing an Asynchronous Add Operation
If you want to perform other work (in parallel) 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. For a list of possible
result codes for an LDAP add operation, see the result code
documentation for the
ldap_add_ext_s()
function.
The following section of code calls ldap_add_ext()
to add the user William Jensen to the directory.
Code Example 8-7 - Performing an 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 );
}
}
}
...
Example: Adding an Entry to the Directory (Synchronous)
The following sample program calls the synchronous
ldap_add_ext_s()
function to add a new user to the directory.
Code Example 8-8 - Synchronous add
#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;
}
Example: Adding an Entry to the Directory (Asynchronous)
The following sample program calls the asynchronous
ldap_add_ext()
function to add a new user to the directory.
Code Example 8-9 - Asynchronous add
#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
To modify an entry:
-
Create an array of
LDAPModstructures representing the changes that need to be made. Use theLDAPModstructure to specify a change to an attribute. -
Call the
ldap_modify_ext()orldap_modify_ext_s(), passing in the array ofLDAPModstructures and a distinguished name of the entry that you want modified.
After you are done, call the
ldap_mods_free()
function to free any
LDAPMod structures
you've allocated.
Specifying the Changes
This section describes the process of specifying changes to an entry.
- Replacing the Values of an Attribute
- Removing Values from an Attribute
- Adding Values to an Attribute
- Removing an Attribute
- Adding an Attribute
- Assembling the List of Changes
Replacing the Values of an Attribute
To replace all existing values of an attribute, create an
LDAPMod structure with
the following:
-
Set the
mod_typefield to the attribute type that you want to change (for example, "telephoneNumber"). -
Set the
mod_valuesfield to the new values of the attribute. -
Set the value of the
mod_opfield toLDAP_MOD_REPLACE.
If you want to specify binary data as berval structures (as opposed to string values), you need to do the following:
-
Instead of using the
mod_valuesfield, use themod_bvaluesfield. - Use the bitwise OR operator ( | ) to combine the value
LDAP_MOD_BVALUESwith the value of themod_opfield.
Note the following:
- If you specify an attribute that does not exist in the entry, the attribute will be added to the entry.
-
If you set a
NULLvalue for the attribute (either by setting themod_valuesfield toNULL, or by setting themod_bvaluesfield toNULLwhen themod_opfield containsLDAP_MOD_BVALUES), the attribute will be removed from the entry.
The following section of code specifies a change that replaces
the values of the telephoneNumber attribute.
Code Example 8-10 - Modifying attribute values
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:
-
Set the
mod_typefield to the attribute type containing the values that you want to remove (for example, "facsimileTelephoneNumber"). -
Set the
mod_valuesfield to the values that you want removed from the attribute. -
Set the value of the
mod_opfield toLDAP_MOD_DELETE.
If you want to specify binary data as berval structures (as opposed to string values), you need to do the following:
-
Instead of using the
mod_valuesfield, use themod_bvaluesfield. -
Use the bitwise OR operator ( | ) to combine the value
LDAP_MOD_BVALUESwith the value of themod_opfield.
Note the following:
- If you remove all values from the attribute, the attribute will be removed from the entry.
-
If you set a
NULLvalue for the attribute (either by setting themod_valuesfield toNULL, or by setting themod_bvaluesfield toNULLwhen themod_opfield containsLDAP_MOD_BVALUES), the attribute will be removed from the entry.
The following example specifies the removal of one of the values
of the facsimileTelephoneNumber attribute in the entry:
Code Example 8-11 - Removing an attribute value
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:
-
Set the
mod_typefield to the attribute type that you want to add values to (for example, "audio"). -
Set the
mod_valuesfield to the new values of the attribute. -
Set the value of the
mod_opfield toLDAP_MOD_ADD.
If the attribute contains binary data (as opposed to string values), you need to do the following:
-
Instead of using the
mod_valuesfield, use themod_bvaluesfield. Make sure to put the values inbervalstructures. -
Use the bitwise OR operator ( | ) to combine the value
LDAP_MOD_BVALUESwith the value of themod_opfield.
Note that if the attribute does not already exist in the entry, the attribute will be added to the entry.
The following example adds values to the audio
attribute to an entry:
Code Example 8-12 - Adding values to an attribute
#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 one of the following ways:
- Remove all values from the attribute.
-
Set the
mod_opfield toLDAP_MOD_REPLACEorLDAP_MOD_DELETEand specifyNULLfor themod_valuesfield.
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.
Assembling the List 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 LDAP API function for
modifying the entry.)
The following section of code creates an array of
LDAPMod structures:
Code Example 8-13 - Assembling a list of changes
... 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 functions:
-
The synchronous
ldap_modify_ext_s()function (see"Performing a Synchronous Modify Operation"). -
The asynchronous
ldap_modify_ext()function (see"Performing an Asynchronous Modify Operation").
For more information about the difference between synchronous and asynchronous functions, see "Calling Synchronous and Asynchronous Functions."
Performing a 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 an LDAP modify request to the server
and blocks until the server sends the results of the operation back
to your client.
The ldap_modify_ext_s() function returns
LDAP_SUCCESS if the operation completed successfully or
an error code if a problem occurred. See the documentation on the
ldap_modify_ext_s()
function for a list of the possible result codes.
The following section of code uses the synchronous
ldap_add_ext_s() function to modify the entry for the
user William Jensen in the directory.
Code Example 8-14 - Performing a 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 );
...
Performing an 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 an LDAP modify request to the server
and returns an LDAP_SUCCESS result code if the request
was successfully sent or it sends 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. For a list of possible
result codes for an LDAP modify operation, see the result code
documentation for the
ldap_modify_ext_s()
function.
The following section of code calls ldap_modify_ext()
to modify the entry for the user William Jensen in the
directory.
Code Example 8-15 - Performing an 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 );
...
Example: Modifying an Entry in the Directory (Synchronous)
The following sample program 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 of the entry and adds a
description attribute to the entry.
Code Example 8-16 - Synchronous modify
#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;
}
Example: Modifying an Entry in the Directory (Asynchronous)
The following sample program 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 of the entry and adds a
description attribute to the entry.
Code Example 8-17 - Asynchronous modify
#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 functions:
-
The synchronous
ldap_delete_ext_s()function (see"Performing a Synchronous Delete Operation"). -
The asynchronous
ldap_delete_ext()function (see"Performing an Asynchronous Delete Operation").
For more information about the difference between synchronous and asynchronous functions, see "Calling Synchronous and Asynchronous Functions."
Performing a 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 an LDAP delete request to the server
and blocks 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. See the documentation on the
ldap_delete_ext_s()
function for a list of the possible result codes.
The following section of code uses the synchronous
ldap_delete_ext_s() function to remove the entry for
the user William Jensen from the directory.
Code Example 8-18 - Synchronous deletion
#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 );
...
Performing an 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 an LDAP 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. For a list of possible
result codes for an LDAP delete operation, see the result code
documentation for the
ldap_delete_ext_s()
function.
The following section of code calls
ldap_delete_ext() to remove the user William
Jensen from the directory.
Code Example 8-19 - Asynchronous deletion
#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 );
...
Example: Deleting an Entry from the Directory (Synchronous)
The following sample program calls the synchronous
ldap_delete_ext_s()
function to delete a user's entry from the directory.
Code Example 8-20 - Synchronous entry deletion
#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;
}
Example: Deleting an Entry from the Directory (Asynchronous)
The following sample program calls the asynchronous
ldap_delete_ext()
function to delete a user's entry from the directory.
Code Example 8-21 - Asynchronous entry deletion
#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 functions:
-
The synchronous
ldap_rename_s()function (see "Performing a Synchronous Renaming Operation"). -
The asynchronous
ldap_rename()function (see "Performing an Asynchronous Renaming Operation").
For more information about the difference between synchronous and asynchronous functions, see"Calling Synchronous and Asynchronous Functions."
For both functions, you can choose to delete the attribute that represents the old relative distinguished name (RDN) (see "Deleting the Attribute from the Old RDN" for details). You can also change the location of the entry in the directory tree (see "Changing the Location of the Entry" for details).
Performing a 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 an LDAP modify DN request to the
server and blocks 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. See the documentation on the
ldap_rename_s()
function for a list of the possible result codes.
The following section of code uses the synchronous
ldap_rename_s() function to change the RDN of the entry
for the user William Jensen in the directory.
Code Example 8-22 - Performing a synchronous modification
#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 );
...
Performing an 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 an LDAP 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 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. For a list of possible
result codes for an LDAP rename operation, see the result code
documentation for the
ldap_rename_s()
function.
The following section of code calls ldap_rename() to
change the RDN of the user William Jensen in the
directory.
Code Example 8-23 - Performing an asynchronous modification
#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. The deleteoldrdn parameter
is best explained through this example. Suppose an entry has the
following values for the cn attribute:
cn: Barbara Jensen cn: Babs Jensen
The following function call adds "Barbie Jensen" to
this list of values and removes the "Barbara Jensen"
value:
ldap_modrdn2( "cn=Barbara Jensen", "cn=Barbie Jensen", 1 );
The resulting entry has the following values:
cn: Barbie Jensen cn: Babs Jensen
If instead a 0 is passed for the deleteoldrdn parameter:
ldap_modrdn2( "cn=Barbara Jensen", "cn=Barbie Jensen", 0 );
the "Barbara Jensen" value is not removed from the entry:
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".
Note that not all LDAP servers support this feature. At this
point in time, the Netscape Directory Server does not support this
feature. If you specify this argument, the Netscape Directory Server
will send back the LDAP result code
LDAP_UNWILLING_TO_PERFORM with the error message
"server does not support moving of entries."
Example: Renaming an Entry in the Directory (Synchronous)
The following sample program calls the synchronous
ldap_rename_s() function
to change the RDN of a user's entry in the directory.
Code Example 8-24 - Synchronous renaming 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;
}
Example: Renaming an Entry in the Directory (Asynchronous)
The following sample program calls the asynchronous
ldap_rename() function to
change the RDN of a user's entry in the directory.
Code Example 8-25 - Asynchronous renaming 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++;
}