Plug-in Guide

Red Hat Directory Server 9

Updated for Directory Server 9.1.2

Marc Muehlfeld

Red Hat Customer Content Services

Petr Bokoč

Red Hat Customer Content Services

Ella Deon Ballard

Red Hat Customer Content Services

Abstract

This guide provides a reference of plug-ins, parameter blocks, and data structure available in the Directory Server API.
This documentation is no longer maintained. For details, see Deprecated Documentation.

Deprecated Documentation

Important

Note that as of June 10, 2017, the support for Red Hat Directory Server 9 has ended. For details, see Red Hat Directory Server Life Cycle policy. Red Hat recommends users of Directory Server 9 to update to the latest version.
Due to the end of the maintenance phase of this product, this documentation is no longer updated. Use it only as a reference!

Preface

This book describes how to write server plug-ins in order to customize and extend the capabilities of the Red Hat Directory Server (Directory Server).

1. Required Concepts

This book is aimed at those who have at least the following general background:
  • An understanding of the Internet and the World Wide Web (WWW).
  • An understanding of the Lightweight Directory Access Protocol (LDAP) and the Directory Server. This book does not duplicate basic information on server administration or LDAP concepts. For such information, see the other manuals in the Red Hat Directory Server documentation set, listed in Section 3, “Additional Reading”.
  • Programming experience in C or C++.

2. Examples and Formatting

Each of the examples used in this guide, such as file locations and commands, have certain defined conventions.

2.1. Command and File Examples

All of the examples for Red Hat Directory Server commands, file locations, and other usage are given for Red Hat Enterprise Linux 5 (64-bit) systems. Be certain to use the appropriate commands and files for your platform.

Example 1. Example Command

To start the Red Hat Directory Server:
service dirsrv start

2.2. Brackets

Square brackets ([]) are used to indicate an alternative element in a name. For example, if a tool is available in /usr/lib on 32-bit systems and in /usr/lib64 on 64-bit systems, then the tool location may be represented as /usr/lib[64].

2.3. Client Tool Information

The tools for Red Hat Directory Server are located in the /usr/bin and the /usr/sbin directories.

Important

The LDAP tools such as ldapmodify and ldapsearch from OpenLDAP use SASL connections by default. To perform a simple bind using a username and password, use the -x argument to disable SASL.

2.4. Text Formatting and Styles

Certain words are represented in different fonts, styles, and weights. Different character formatting is used to indicate the function or purpose of the phrase being highlighted.
Formatting Style Purpose
Monospace font Monospace is used for commands, package names, files and directory paths, and any text displayed in a prompt.
Monospace 
with a
background
This type of formatting is used for anything entered or returned in a command prompt.
Italicized text Any text which is italicized is a variable, such as instance_name or hostname. Occasionally, this is also used to emphasize a new term or other phrase.
Bolded text Most phrases which are in bold are application names, such as Cygwin, or are fields or options in a user interface, such as a User Name Here: field or Save button.
Other formatting styles draw attention to important text.

Note

A note provides additional information that can help illustrate the behavior of the system or provide more detail for a specific issue.

Important

Important information is necessary, but possibly unexpected, such as a configuration change that will not persist after a reboot.

Warning

A warning indicates potential data loss, as may happen when tuning hardware for maximum performance.

3. Additional Reading

The Red Hat Directory Server Deployment Guide describes many of the basic directory and architectural concepts that you need to deploy, install, and administer a directory service successfully.
When you are familiar with Directory Server concepts and have done some preliminary planning for your directory service, install the Directory Server. The instructions for installing the various Directory Server components are contained in the Red Hat Directory Server Installation Guide. Many of the scripts and commands used to install and administer the Directory Server are explained in detail in the Red Hat Directory Server Configuration, Command, and File Reference.
The Directory Server Administrator's Guide describes how to set up, configure, and administer Red Hat Directory Server and its contents.
The document set for Directory Server contains the following guides:
  • Red Hat Directory Server Release Notes contain important information on new features, fixed bugs, known issues and workarounds, and other important deployment information for this specific version of Directory Server.
  • Red Hat Directory Server Deployment Guide provides an overview for planning a deployment of the Directory Server.
  • Red Hat Directory Server Administrator's Guide contains procedures for the day-to-day maintenance of the directory service. Includes information on configuring server-side plug-ins.
  • Red Hat Directory Server Configuration, Command, and File Reference provides reference information on the command-line scripts, configuration attributes, schema elements, and log files shipped with Directory Server.
  • Red Hat Directory Server Installation Guide contains procedures for installing your Directory Server as well as procedures for migrating from a previous installation of Directory Server.
  • Red Hat Directory Server Plug-in Programmer's Guide describes how to write server plug-ins in order to customize and extend the capabilities of Directory Server.
  • The Red Hat Directory Server Performance Tuning Guide contains features to monitor overall Directory Server and database performance, to tune attributes for specific operations, and to tune the server and database for optimum performance.
For the latest information about Directory Server, including current release notes, complete product documentation, technical notes, and deployment information, see the Red Hat Directory Server documentation site at https://access.redhat.com/site/documentation/Red_Hat_Directory_Server/.

4. Giving Feedback

If there is any error in this Plug-in Programmer's Guide or there is any way to improve the documentation, please let us know. Bugs can be filed against the documentation for Red Hat Directory Server through Bugzilla, http://bugzilla.redhat.com/bugzilla. Make the bug report as specific as possible, so we can be more effective in correcting any issues:
  1. Select the Red Hat Directory Server product.
  2. Set the component to Doc - plug-in-programmers-guide.
  3. Set the version number to 9.0.
  4. For errors, give the page number (for the PDF) or URL (for the HTML), and give a succinct description of the problem, such as incorrect procedure or typo.
    For enhancements, put in what information needs to be added and why.
  5. Give a clear title for the bug. For example, "Incorrect command example for setup script options" is better than "Bad example".
We appreciate receiving any feedback — requests for new sections, corrections, improvements, enhancements, even new ways of delivering the documentation or new styles of docs. You are welcome to contact Red Hat Content Services directly at docs@redhat.com.

Part I. Introduction to Directory Server Plug-ins

Chapter 1. An Overview of Directory Server Plug-ins

This chapter introduces you to Red Hat Directory Server plug-ins and discusses the different types of plug-ins that you can write.
If you have already written a plug-in for Directory Server, refer to Section 1.4, “Using Directory Server Plug-in APIs” for information on migrating your plug-in to the latest version of Directory Server.

1.1. About Directory Server Plug-ins

If you want to extend the capabilities of the Directory Server, you can write your own Directory Server plug-in. A server plug-in is a shared object or library that contains custom functions that you write.
By writing your own plug-in functions, you can extend the functionality of the Directory Server. The following are some examples of what you can do with Directory Server plug-ins:
  • You can design an action that the Directory Server performs before the server processes an LDAP action. For example, you can write a custom function to validate data before the server performs an LDAP operation on the data.
  • You can design an action that the Directory Server performs after the server successfully completes an LDAP operation. For example, you can send mail to a client after an LDAP operation is successfully completed.
  • You can define extended operations, as defined in the LDAP v3 protocol.
  • You can provide alternative matching rules when comparing certain attribute values.

1.2. How Directory Server Plug-ins Work

You can configure Directory Server to load your plug-ins when Directory Server is started. After the plug-in has loaded, the Directory Server will resolve calls made to your plug-in functions as it processes the LDAP requests contained in your applications.
Internally, the Directory Server has hooks that allow you to register your own functions to be called when specific events occur. For example, the Directory Server has hooks to call a registered plug-in in the following situations:
  • Before preforming an LDAP operation (for example, before an entry is added to the directory).
  • When adding, modifying, removing, renaming, or searching for entries in the database.
  • After performing an LDAP operation (for example, after an entry is added to the directory).
  • Before writing an entry to the database.
  • After reading an entry from the database.
  • When processing an extended operation.
  • When indexing an attribute.
  • When filtering search result candidates based on an attribute.
When you register your plug-in functions, you specify the function type and the plug-in type. Together, these specifications indicate when the function is called. Refer to Section 1.3, “Types of Directory Server Plug-ins”.

1.2.1. Calling Directory Server Plug-in Functions

At specific LDAP events, the Directory Server calls all plug-in functions that are registered for that event. For example, before performing an LDAP add operation (an add event), the server calls all plug-in functions registered as pre-operation add functions. When the add operation is completed, the server will call all registered post-operation add functions.
In most plug-in function calls, the server passes a parameter block structure (also called a pblock or Slapi_PBlock) to the function. The parameter block contains data relevant to the operation. In most Directory Server plug-in functions you write, you access and modify the data in the parameter block.
For example, when the Directory Server receives an LDAP add request, the server does the following:
  1. Parses the request, and retrieves the new DN and the entry to be added.
  2. Places pointers to the DN and the entry in the parameter block.
  3. Calls any registered pre-operation add functions, passing the parameter block to these functions.
  4. Calls the registered database add function (which is responsible for adding the entry to the directory database), and passes to it the parameter block.
  5. Calls any registered post-operation add functions, passing the parameter block to these functions.
If you are writing a function that is invoked before an LDAP operation is performed, you can prevent the operation from being performed. For example, you can write a function that validates data before a new entry is added to the directory. If the data is not valid, you can prevent the LDAP add operation from occurring and return an error message to the LDAP client.
In some situations, you can also set the data that is used by the server to perform an operation. For example, in a pre-operation add function, you can change an entry before it is added to the directory.

1.2.2. The Directory Server Architecture

Internally, the Directory Server consists of two major subsections, the front-end and the backend.
The front-end receives LDAP requests from clients and processes those requests. When processing requests, the front-end calls functions in the backend to read and write data. The front-end then sends the results back to the client.
The backend reads and writes data to the database containing the directory entries. The backend abstracts the database from the front-end. The data stored in a backend is identified by the suffixes that the backend supports. For example, a backend that supports the dc=example,dc=com suffix contains directory entries that end with that suffix.
The following diagram illustrates the Directory Server architecture.
Directory Server Architecture

Figure 1.1. Directory Server Architecture

1.3. Types of Directory Server Plug-ins

Several types of plug-ins can be written for Directory Server:
  • Pre-operation/data validation
    The server calls a pre-operation/data validation plug-in function before performing an LDAP operation.
    The main purpose of this type of plug-in is to validate data before the data is added to the directory or before it is used in an operation. For example, a bind pre-operation plug-in can be used to validate authentication or even to provide alternate authentication mechanisms, if passwords are stored in an external database.
  • Post-operation/data notification
    The server calls a post-operation/data notification plug-in function after performing an LDAP operation.
    The main purpose of this type of plug-in is to invoke a function after a particular operation is executed. For example, you can write a plug-in that sends email to users if their entries are modified.
    The post-operation plug-ins are called after an operation completes and returns the results for both success and failure. The returned result code can be pulled from the previous operation using the SLAPI_RESULT_CODE pblock parameter. For example:
    int return_code;
    if (slapi_pblock_get(pb, SLAPI_RESULT_CODE, &return_code) != 0) {
       // something went wrong
    }
  • Entry storage and entry fetch
    The server calls an entry storage plug-in function immediately before writing data to the database backend. The server calls entry fetch plug-in functions after retrieving an entry from the database backend.
    For example, you can create an entry storage plug-in that encrypts an entry before it is saved to the database and an entry fetch plug-in that decrypts an entry after it is read from the database.
  • Extended operation
    The server calls an extended operation plug-in function when the client requests an operation by OID. Extended operations are defined in LDAP v3 and are described in more detail in Chapter 10, Writing Extended Operation Plug-ins.
  • Syntax
    The server calls a syntax plug-in function when getting a list of possible candidates for a search. The server also calls these functions when adding or deleting values from certain attribute indexes.
    Syntax plug-in functions can define the comparison operations used in searches. For example, you could use a syntax plug-in function to define how the equals comparison works for case-insensitive strings.
  • Matching rule
    The server calls matching rule plug-in functions when the client sends a search request with an extensible matching search filter. You can also write matching rule plug-in functions that the server calls when indexing attributes for the backend database.
The following diagram illustrates how some of these different plug-in types fit into the Directory Server architecture.
Architecture of the Directory Server and Server Plug-ins

Figure 1.2. Architecture of the Directory Server and Server Plug-ins

1.4. Using Directory Server Plug-in APIs

When using Directory Server plug-in APIs, you should be aware of the following:
  • Plug-in files and examples are installed separately from other Directory Server packages, available at the Fedora Directory Server CVS repos, https://git.fedorahosted.org/cgit/389/ds.git/tree/ldap/servers/plugins and https://git.fedorahosted.org/cgit/389/ds.git/tree/ldap/servers/slapd/test-plugins. These sample plug-in files can be installed in any directory.
  • The main header file is install_directory//ldapserver/ldap/servers/slapd/slapi-plugin.h. On some systems, the 389-ds-base-devel package installs this header file automatically in /usr/include/dirsrv/slapi-plugin.h.
  • Plug-in directives are contained in the /etc/dirsrv/slapd-instance_name/dse.ldif file. These plug-in configuration entries can be added or modified using LDAP tools like ldapmodify or by stopping the server and manually editing the dse.ldif file. (Either way, the server must be restarted before the plug-in changes take effect.)
    See chapter 2, "Core Server Configuration Reference," in the Configuration, Command, and File Reference for information on the syntax of the dse.ldif file.
  • Database plug-ins are not supported in Directory Server. Be sure to use the pre-operation, post-operation, or extended operation API to register plug-in functions.
  • To comply with IPv6, Directory Server Plug-in Programmer's Guide can use the SLAPI_CONN_CLIENTEDADDR and SLAPI_CONNSERVERADDR parameters to allow plug-ins to recognize the IP address of the LDAP client and server. These new parameters use the Netscape Portable Runtime (NSPR) PRNetAddr structure for storing the IP addresses. Because of this, the NSPR files are either shipped with Directory Server or are available from the operating system's nspr-devel package, with the header files installed in /usr/include/nspr4.
    The NSPR API allows compliant applications to use system facilities such as threads, thread synchronization, I/O, interval timing, atomic operations, and several other low-level services independent of platform.

1.5. Deprecated Functions and Replacements

Several functions have been deprecated in the Directory Server plug-in API. The deprecated functions are still supported for backward compatibility. They are, however, no longer documented and should not be used.
Table 1.1, “Deprecated Functions and Suggested Replacements” lists the deprecated functions and the functions to use in their place.

Table 1.1. Deprecated Functions and Suggested Replacements

Deprecated Function Suggested Replacement Function
These functions deal with bervals. These functions are deprecated and their use is not recommended. For each deprecated function, a corresponding function is listed in slapi-plugin.h with an _sv extension that uses Slapi_Values instead of bervals.
slapi_entry_attr_merge() slapi_entry_attr_merge_sv()
slapi_entry_add_values() slapi_entry_add_values_sv()
slapi_entry_delete_values() slapi_entry_delete_values_sv()
slapi_entry_attr_replace() slapi_entry_attr_replace_sv()
slapi_attr_get_values() slapi_attr_value_find()
slapi_attr_get_oid() slapi_attr_get_oid_copy()
slapi_pw_find() slapi_pw_find_sv()
slapi_call_syntax_values2keys() slapi_call_syntax_values2keys_sv()
slapi_call_syntax_assertion2keys_ava() slapi_call_syntax_assertion2keys_ava_sv()
slapi_call_syntax_assertion2keys_sub() slapi_call_syntax_assertion2keys_sub_sv()
slapi_entry_attr_hasvalue() slapi_entry_attr_has_syntax_value()
The following internal-operation calls are deprecated. The new internal operation functions that are defined in slapi-plugin.h take a Slapi_PBlock for extensibility and support the new plug-in configuration capabilities.
slapi_search_internal_callback() slapi_search_internal_callback_pb()
slapi_search_internal() slapi_search_internal_pb()
slapi_modify_internal() slapi_modify_internal_pb()
slapi_add_internal() slapi_add_internal_pb()
slapi_delete_internal() slapi_delete_internal_pb()
slapi_modrdn_internal() slapi_modrdn_internal_pb()
The following functions are not multi-thread safe; they return a pointer to unprotected data. Use the new functions in slapi-plugin.h that end in _copy() instead.
slapi_get_supported_controls() slapi_get_supported_controls_copy()
slapi_get_supported_extended_ops() slapi_get_supported_extended_ops_copy()
slapi_get_supported_saslmechanism() slapi_get_supported_saslmechanisms_copy()
All of these functions are designed to work with entry DNs, but they no longer work with the Slapi_DN structure. These DN functions have been deprecated. New DN management functions, slapi_sdn_*, have been added to slpi-plugin.h.
slapi_dn_isparent() slapi_sdn_isparent()
slapi_dn_issuffix() slapi_sdn_issuffix()
slapi_dn_normalize() slapi_sdn_get_ndn()
slapi_dn_parent() slapi_sdn_get_parent()
slapi_dn_plus_rdn() slapi_sdn_add_rdn()
slapi_isbesuffix() slapi_be_issuffix()
slapi_dn_beparent() slapi_sdn_get_backend_parent()
slapi_dn_ignore_case()
slapi_sdn_get_ndn() (to normalize the case)
slapi_sdn_compare() (to compare DNs, regardless of case)

Chapter 2. Writing and Compiling Plug-ins

This chapter provides an introduction on how to write and compile Red Hat Directory Server. Chapter 3, Configuring Plug-ins describes how to load the plug-in into the Directory Server configuration after it has been successfully compiled.
If you have already written a plug-in for the Directory Server, see Section 1.4, “Using Directory Server Plug-in APIs” for information on migrating a custom plug-in to the latest version of Directory Server.

2.1. Writing a Plug-in Function

To write a Directory Server plug-in, the plug-in code must:
  • Include the API header file.
  • Set the function parameters using the parameter block.
  • Call the front-end.
  • Specify the function return value.

Important

Any custom plug-in files must be located in the default plug-ins directory, install_directory/ldapserver/ldap/servers/plugins on Red Hat Enterprise Linux 5 (64-bit). SELinux policies set rules on what directories the Directory Server processes are allowed to access, and any required files (such as plug-ins) must be in the default directories or the server cannot load them.
If the plug-in files are not in the default location, then the SELinux policies must be manually updated to include the alternate location.
For additional information on writing specific plug-in types, see the following sections:

2.1.1. Including the API Header File

The interface to the Directory Server plug-in API is located in the slapi-plugin.h header file. Include this header file in all custom plug-ins:
#include "slapi-plugin.h"
Then provide the path to this file with the compiler command line:
gcc ... -I install_directory//ldapserver/ldap/servers/slapd myplugin.c
On many platforms, the header file is provided by the 389-ds-base-devel package. This package installs the file in /usr/include/dirsrv, so the relative path can be used in the include statement — #include .dirsrv/slapi-plugin.h — and there is no need to set the path in the -I since the compiler will find it in the default location. This is recommended.

2.1.2. Passing Data with Parameter Blocks

Plug-in functions often make use of the Slapi_PBlock parameter block (pblock) for passing information to and from the Directory Server. All functions use a pblock.
These functions take a single argument of type Slapi_PBlock* to the Directory Server. This argument contains the parameter values needed to complete the function request. A plug-in function typically has a prototype similar to the following:
int myFunction( Slapi_PBlock *pb [optional_arguments );
In this prototype, pb is the parameter block that contains the parameters pertaining to the operation or function.
For example, the parameter block for an add operation will contain the target DN and the entry to be added; the parameter block for a bind operation will contain the DN of the user, the authentication method, and the user's credentials.

2.1.3. Working with Parameter Blocks

In the functions that you write, you set values in the parameter block that pertain to the operation you are performing. You can also get data from the parameter block that you can use within the plug-in functions. This process is described in Section 2.1.3.1, “Getting Data from the Parameter Block”.
You can also set values in the parameter block during the processing of the plug-in functions. The Directory Server can then use the new data values to complete an operation which it might be processing. This process is described in Section 2.1.3.2, “Setting Data in the Parameter Block”.
Some of the data that you can retrieve from the parameter block includes entries, attributes, search filters, and distinguished names (DNs). After you have retrieved a piece of data, you can manipulate it using the front-end API functions. For example, you can use front-end API functions to verify that an entry complies with the schema or you can split up a search filter into its individual components. This process is described in Section 2.1.4, “Calling Front-end Functions”.

2.1.3.1. Getting Data from the Parameter Block

When the Directory Server calls the plug-in function, it passes any relevant data to the function in a parameter block defined as a data type found in Slapi_PBlock. To access the data in a parameter block, call the slapi_pblock_get() function.

Note

slapi_pblock_get() often returns a pointer to the actual data. When you call custom functions to modify the value retrieved by slapi_pblock_get(), you are modifying the actual data in the parameter block, not a copy of the data.
In Example 2.1, “searchdn_preop_search() Function”, the searchdn_preop_search() function gets the DN of the base DN for the LDAP search operation. It then normalizes the DN, converts all characters to lowercase, and writes the converted DN to the error log. The function makes a copy of the DN so that the actual data in the pblock are not changed.

Note

The data in the pblock can be modified, but this is not common, and be careful doing that.
Since there is a a copy of the data (using slapi_ch_strdup()), free the memory at the end (using slapi_ch_free_string()).

Example 2.1. searchdn_preop_search() Function

#include "slapi-plugin.h"
...
int searchdn_preop_search( Slapi_PBlock *pb )
{
	Slapi_DN *dn;
	char *mydn;
	/* Indicate the point when the plug-in starts executing */
	slapi_log_error( SLAPI_LOG_PLUGIN, "searchdn_preop_search" ,"*** PREOPERATION SEARCH PLUGIN ***\n" );
	
	/* Get the base DN of the search from the parameter block. */
	slapi_pblock_get( pb, SLAPI_SEARCH_TARGET, &dn);

        /* make a copy of the DN */
        mydn = slapi_ch_strdup(dn);
	
	/* Normalize the copy of the DN and convert it to lowercase */
	slapi_dn_normalize_case( mydn );
	
	/* Log the normalized DN */
	slapi_log_error( SLAPI_LOG_PLUGIN, "searchdn_preop_search" ,"Normalized DN: %s\n" , mydn );

        /* more processing . . . */

        /* free the copy */
        slapi_ch_free_string(&mydn);
	
	return( 0 );
}
SLAPI_SEARCH_TARGET identifies the parameter in the parameter block that contains the base DN of the search. The plug-in should arrange to release the resources for any data allocated. In this case, the plug-in should also provide a stop callback which would get the db from the pblock and free the resources associated with it.
For a complete listing of the parameter block IDs, see Part V, “Parameter Block Reference”.

2.1.3.2. Setting Data in the Parameter Block

To modify the value of a parameter in the parameter block, call the slapi_pblock_set() function. For example, you can call slapi_pblock_set() to change the value of the SLAPI_PRIVATE parameter, which stores private data for the plug-in.
In the following example, the ldif_back_init() function sets the value of the SLAPI_PRIVATE parameter to the context of the database.
#include "slapi-plugin.h";
...
int
ldif_back_init( Slapi_PBlock *pb )
{
	LDIF *db; /* context of the database */
	...
	/* Allocate space for the database context, which contains information about the 
	database and a pointer to the list of entries. */
	
	if ( slapi_pblock_set( pb, SLAPI_PRIVATE, (void *) db ) == -1 )
	{
		slapi_log_error( SLAPI_LOG_PLUGIN, "ldif_back_init" ,
		"Unable to store database information\n" );
	}
	...
}
This example uses the slapi_log_error() function to notify the user if an error occurred.
In this code example, SLAPI_PRIVATE identifies the parameter in the parameter block that contains private data for use in the database functions. For a complete listing of the parameter block IDs, see Part V, “Parameter Block Reference”.

2.1.4. Calling Front-end Functions

The types of data that you can get from a parameter block include entries, attributes, distinguished names, and search filters. If you want to manipulate these data items, you can call the associated front-end API functions provided with the Directory Server. For example, using the front-end API functions, you can:
  • Write messages to the error log.
  • Get the attributes of an entry.
  • Get or set the DN of an entry.
  • Add or delete the values of an attribute.
  • Determine the OID of an attribute.
  • Determine the type of a search filter.
For more information on the front-end API, see Chapter 5, Frontend API Functions and Part IV, “Function Reference”.

2.1.5. Plug-in Return Values

If the plug-in function is successful, it should return 0 to the front-end. If it is not successful, it should return a non-zero value, and you should call the front-end API function slapi_log_error() to log an error message to describe the problem. Refer to Section 5.1, “Logging Messages” for more information.
In some cases, you may need to send an LDAP result back to the client. For example, if you are writing a pre-operation bind function and an error occurs during the processing of the function, the function should return a non-zero value, log an error message, and send the appropriate LDAP result code back to the client. For information on the appropriate result code to return to the client, see the chapter that documents the type of plug-in you are writing.

2.2. Writing Plug-in Initialization Functions

Before the Directory Server can call the plug-in function, the function must be properly initialized. To do this, you must write an initialization function for the server plug-in. The initialization function should:
  1. Specify the plug-in compatibility version.
  2. Register each of the plug-in functions.
  3. Return a value to the Directory Server.

Note

The initialization function should not do anything more than these three steps. For example, the init function should not attempt to perform an internal search or other internal operation, because the all of the subsystems are not up and running during the init phase.
To perform additional configuration or initialization, use a start function. This function is specified by using slapi_pblock_set() with the SLAPI_PLUGIN_START_FN parameter in the initialization function.
Your initialization function should have a prototype similar to the following:
int my_init_function( Slapi_PBlock pb );
In the initialization function, the Directory Server passes a single argument of the type Slapi_PBlock*.

2.2.1. Specifying Directory Server Compatibility

Specify the compatibility version of the plug-in so that the Directory Server can determine whether it supports the plug-in.
To specify the plug-in compatibility version, call the slapi_pblock_set() function, and set the SLAPI_PLUGIN_VERSION_03 parameter to the version number associated with the plug-in. For example:
slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_03);
Plug-in version 3 (SLAPI_PLUGIN_VERSION_03) is compatible with versions 6.x and later of the Directory Server. Two other plug-in versions are available for backward compatability with older version of Directory Server; otherwise, these versions are deprecated:
  • SLAPI_PLUGIN_VERSION_01 is compatible with versions 3.x and 4.x of the Directory Server.
  • SLAPI_PLUGIN_VERSION_02 is compatible with version 4.x of the Directory Server.

2.2.2. Specifying Information about the Plug-in

You specify information about the plug-in, such as a description, with the Slapi_PluginDesc structure. For details on this data structure, see Section 14.30, “Slapi_PluginDesc”.
It is recommended that you include a plug-in description because the Red Hat Console displays this information as part of the server configuration information.
To specify plug-in information, call the slapi_pblock_set() function, and set the SLAPI_PLUGIN_DESCRIPTION parameter to this structure. For example:
Specifying Plug-in Information
/* Specify information about the plug-in */
Slapi_PluginDesc mypdesc = { "test-plugin" , "example.com" "0.5" , "sample pre-operation plugin" };
...
/* Set this information in the parameter block */
slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION, (void*)&mypdesc );
This example code specifies the following plug-in information:
  • The unique identifier for the server plug-in is test-plugin.
  • The vendor of the server plug-in is example.com.
  • The version of the server plug-in is 0.5.
    This version is intended to be used for tracking purposes only; it is not the same as the server compatibility version number specified by the SLAPI_PLUGIN_VERSION parameter (see Section 2.2.1, “Specifying Directory Server Compatibility” for details on this parameter). As you make changes to the plug-in code, you can track the version distributed using the number contained in the Slapi_PluginDesc structure.
  • The description of the server plug-in is contained in the data structure value sample pre-operation plug-in.

2.2.3. Registering Your Plug-in Functions

Whether the plug-in is registered through the initialization function depends on the type of function being registered.
For some plug-in types, you do not need to register the plug-in function from within the initialization function. For example, you register entry store and entry fetch plug-ins by specifying the function names in the plugin directive in the dse.ldif file.
For other plug-in types, such as pre-operation plug-ins and post-operation plug-ins, the Directory Server gets the pointer to the function from a parameter in the initialization function parameter block. In these cases, you use the slapi_pblock_set() function to specify the name of the plug-in function.
The full list parameters that you can use to register the plug-in functions are listed in Chapter 52, Parameters for Registering Plug-in Functions.
For example, if you want to register searchdn_preop_search() as a pre-operation search function, include the following code in the initialization function:
slapi_pblock_set( pb, SLAPI_PLUGIN_PRE_SEARCH_FN, (void *) searchdn_preop_search )
SLAPI_PLUGIN_PRE_SEARCH_FN is the parameter that specifies the pre-operation plug-in function for the LDAP search operation.

Note

If the plug-in functions are not registered, the Directory Server will not call them. All custom plug-in functions should be registered.
More than one plug-in function can be registered in the initialization function; it is not necessary to write an initialization function for each plug-in function that needs to be registered. However, define a different initialization function for each type of plug-in being registered. An object type plug-in can register any type of plug-in in its init function, so when writing a plug-in that must perform several different types of operations, an object plug-in is probably the best approach.

2.2.4. Returning a Value to the Directory Server

If the initialization function is successful, it should return 0. If an error occurs, it should return -1, in which case the Directory Server will exit.

2.2.5. Example of an Initialization Function

The following is an example of an initialization function that registers the pre-operation plug-in function searchdn_preop_search(). After the initialization function returns, the server will call searchdn_preop_search() before each LDAP search operation is executed.
#include "slapi-plugin.h"
...
#ifdef _WIN32
__declspec(dllexport)
#endif

searchdn_preop_init( Slapi_PBlock *pb )
{
	/*Specify the version of the plug-in (set this to "03" )*/
	if ( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_03 ) != 0 ||
	
	/* Set up theserver to call searchdn_preop_search()
	before each LDAP search operation. */
	
	slapi_pblock_set( pb, SLAPI_PLUGIN_PRE_SEARCH_FN, (void *)searchdn_preop_search ) !=0 ) {
	
		/* If a problem occurs, log an error message, return -1.*/
		slapi_log_error(SLAPI_LOG_PLUGIN, "searchdn_preop_init" ,
		"Error registeringfunction.\n" );
		return( -1 );
	}
	
	/*If the plug-in was successfully registered, log a
	message and return 0. */
	slapi_log_error( SLAPI_LOG_PLUGIN, "searchdn_preop_init" ,
	"Plug-in successfully registered.\n" );
	return( 0 );
}

2.3. Compiling a Directory Server Plug-in

Keep in mind the following tips when compiling the server plug-in:
  • Compile and link the code as a shared object or library.
    On Red Hat Enterprise Linux, use -shared with gcc:
    gcc -shared
    On Solaris, use this as the link command:
    ld -G objects -o shared_object
    Some compilers require special flags to be used when compiling code a shared object. On Linux, this is done with the -fPIC flag with gcc to generate position-independent code. On Solaris, this uses the -KPIC flag. Consult the documentation for the platform compiler and linker for details.
  • Ensure that the directory with the slapi-plugin.h file is in the include path directive. For example:
    gcc -I install_directory//ldapserver/ldap/servers/slapd
    It is also possible to define the location of the header file in the plug-in file. Some platforms install the header file with the 389-ds-base-devel package, which installs the header file in the /usr/include/dirsrv. In that case, it is not necessary to specify the full path in the plug-in file.
    #include dirsrv/slapi-plugin.h
  • All plug-in functions can be compiled in a single library. Although different types of plug-in functions can be included in the same library, separate initialization functions need to be written for each type of plug-in function. It is also possible to use an object type plug-in.
    See Chapter 3, Configuring Plug-ins for details on how to specify each initialization function in a directive for a specific type of plug-in.
Example 2.2, “Makefile for Example Plug-ins” assumes that 389-ds-base-devel package has been installed or that the header file, slapi-plugin.h, is in /usr/include/dirsrv.

Example 2.2. Makefile for Example Plug-ins

# Makefile for Directory Server plug-in examples
#
CC = gcc
LD = gcc
CFLAGS = -fPIC
LDFLAGS = -shared
OBJS = testsaslbind.o testextendedop.o testpreop.o testpostop.o testentry.o
all: libtest-plugin.so
libtest-plugin.so: $(OBJS)
$(LD) $(LDFLAGS) -o $@ $(OBJS)
.c.o:
$(CC) $(CFLAGS) -c $<
clean:
-rm -f $(OBJS) libtest-plugin.so

Chapter 3. Configuring Plug-ins

After compiling the server plug-in, configure the Red Hat Directory Server so that it correctly loads the plug-in. The following sections describe this process.

3.1. Creating a Plug-in Configuration File

To add the plug-in to the Directory Server configuration, you need to create an LDIF representation of the plug-in entry, add the plug-in entry to the Directory Server configuration, and reload the server configuration. This section illustrates how to create the plug-in entry. Section 3.2, “Loading the Plug-in Configuration File” explains how to add the plug-in entry to the Directory Server configuration and reload the server configuration.

Important

Any custom plug-in files must be located in the default plug-ins directory, install_directory/ldapserver/ldap/servers/plugins on Red Hat Enterprise Linux 5 (64-bit). SELinux policies set rules on what directories the Directory Server processes are allowed to access, and any required files (such as plug-ins) must be in the default directories or the server cannot load them.
If the plug-in files are not in the default location, then the SELinux policies must be manually updated to include the alternate location.
The plug-in configuration file must be an LDIF file written in ASCII format. The following listing shows the contents of an example plug-in configuration file.

Example 3.1. An Example Plug-in Configuration File

dn: cn=Example Plug-in,cn=plugins,cn=config
objectclass: top
objectclass: nsSlapdPlugin
objectclass: extensibleObject
cn: Example Plug-in
nsslapd-pluginpath: /servers/lib/test-plugin.so
nsslapd-plugininitfunc: searchdn_preop_init
nsslapd-plugintype: preoperation
nsslapd-pluginenabled: on
nsslapd-pluginid: Example Pre-operation Plug-in
nsslapd-pluginversion: 1.0
nsslapd-pluginvendor: Example Corporation
nsslapd-plugindescription: This plug-in does ...
nsslapd-pluginPrecedence: 1
This example plug-in configuration file defines a plug-in as follows:
  • Line 1 sets the DN of the plug-in, which identifies the plug-in:
    dn: cn=Example Plug-in,cn=plugins,cn=config
    Here, the common name of the plug-in is set to Example Plug-in. The remainder of the DN entry (cn=plugins,cn=config) places the entry in the database tree that contains the configuration settings for plug-ins.
  • Lines 2-4 declare the object classes of the plug-in.
  • Line 5 sets the common name of the plug-in to Example Plug-in.
  • Line 6 defines the absolute path to the library that implements the plug-in:
    nsslapd-pluginpath:/servers/lib/test-plugin.so
  • Line 7 identifies the initialization function that the server calls to register the plug-in. In this example, the initialization is set to searchdn_preop_init. For information on implementing initialization functions, refer to Section 2.2, “Writing Plug-in Initialization Functions”.
  • Line 8 specifies the type of plug-in. In this case, it is a pre-operation plug-in. For a complete list of the types of plug-in you can declare, refer to Section 3.1.3, “Summary of Plug-in Directives”.
  • Line 9 specifies whether the plug-in is active by default. The nsslapd-pluginenabled attribute can have a value of either on or off. The following line specifies that the plug-in is active by default:
    nsslapd-pluginenabled: on
    The Directory Server Console can also activate or deactivate the plug-in after it has been loaded.

    Note

    Whenever plug-in configuration is edited — as when a plug-in is activated or deactived — then the server must be restarted for the plug-in changes to take effect.
  • Line 10 uses the nsslapd-pluginid attribute to set the name of the plug-in. The name that you specify here will show up in the Directory Server Console. In this example, the plug-in identification is set to Example Pre-operation Plug-in.
  • Line 11 sets the version number of the plug-in. This version number is also displayed in the Directory Server Console and is used to track the version of the distributed plug-in. It does not indicate the Directory Server compatibility; this is defined by the plug-in version number described in Section 2.2.1, “Specifying Directory Server Compatibility”.
  • Line 12 identifies the vendor or author of the plug-in. In the following line, the vendor is set to Example Corporation:
    nsslapd-pluginvendor: Example Corporation
  • Line 13 sets the description of the plug-in. This is the description visible through the Directory Server Console.
  • Line 14 sets the plug-in precedence. This defines the priority that the plug-in has in the execution order of plug-ins for an operation.

3.1.1. Setting Plug-in Dependencies

A plug-in can be dependent on one or more different plug-ins. Any specified plug-in dependencies must start correctly before the associated plug-in will start.
There are two attributes in the plug-in configuration file that specify the dependencies of the plug-in:
  • nsslapd-plugin-depends-on-named
  • nsslapd-plugin-depends-on-type
Each of these attributes can take multiple values, meaning that the plug-in depends on one or more other plug-ins.

3.1.1.1. Specific Plug-in Dependencies

If you specify the nsslapd-plugin-depends-on-named attribute in the plug-in configuration file, set its value to the names of one or more plug-ins. For example, in the plug-in configuration file, you could specify the following:
nsslapd-plugin-depends-on-named: my_pluginA 
nsslapd-plugin-depends-on-named: vendor_pluginB
In this example, the plug-in depends on two specifically named plug-ins: my_pluginA and vendor_pluginB. This configuration line indicates that before the plug-in can be loaded, the two specifically named plug-ins must be loaded. If either of these two plug-ins fails to load, the Directory Server will exit with a -1 error code.

3.1.1.2. Plug-in Type Dependencies

If you specify the nsslapd-plugin-depends-on-type attribute in the plug-in configuration file, set its value to one or more plug-in types. For example, in the plug-in configuration file, you could specify the following:
nsslapd-plugin-depends-on-type: syntax
This configuration line indicates that the plug-in depends on any plug-in of the type syntax. If there is a configured plug-in of type syntax, it must be successfully loaded before the plug-in can be loaded; otherwise, the Directory Server will exit with a -1 error code.
If you specify a plug-in type dependency, the Directory Server will search for any and all plug-ins of the types specified. If none are found, processing will continue without errors. However, the Directory Server must load all plug-ins of the types specified before it can load the plug-in. For a complete list of the supported plug-in types, refer to the Section 3.1.3, “Summary of Plug-in Directives”.

3.1.2. Specifying the Order of Plug-ins

Generally, plug-ins are not called in a specific order. As in, it is not possible to define that Preoperation Plug-in A is always called before Preoperation Plug-in B. Ideally, plug-ins should be written so that they function correctly irrespective of the order in which they are called.
It can be convenient, however, to set one plug-in to complete its job before the next plug-in is executed. This can allow more complex interactions between plug-ins and more specific functionality for plug-ins.
To set a general plug-in order (within a plug-in type), define a precedence for a plug-in. The precedence sets a value (between 1 and 99) on the plug-in priority, and high-priority plug-ins are called and completed first, going down the line in precedence. The default, if no precedence is set, is 50.
Plug-in precedence sets the execution order for plug-ins of the same type. A precedence of 5 on a preoperation plug-in only matters when other preoperation plug-ins are called of an operation. It doesn't affect the execution order of other types of plug-ins called in the operation.
The plug-in precedence is set in the nsslapd-pluginPrecedence attribute.
nsslapd-pluginPrecedence: 12
Although the plug-in precedence can be set on any plug-in, it is really only relevant for preoperation and postoperation plug-ins. Other plug-in types, like extended operation or matching rule plug-ins, implement callbacks to support specific data types or operations, rather than being called with all other plug-ins of that time for normal LDAP operations.

Note

Plug-in precedence is not the same as plug-in dependence. Dependencies determine the plug-in startup and shutdown order. Precedence determines the execution order for plug-ins in LDAP operations. The plug-in dependencies do not affect the plug-in precedence, and vice versa.
The server loads plug-ins of the same precedence in alphabetical order, determined by standard ASCII ordering of the cn value of the plug-in entry. (The cn appears in the plug-in configuration entry under cn=plugins,cn=config in the dse.ldif file.) Therefore, plug-in names can be used as an extra control measure for the order that plug-ins are loaded and executed.

3.1.3. Summary of Plug-in Directives

The following table summarizes the different types of plug-ins that you can specify in the plug-in configuration file.

Table 3.1. Directives for Specifying Different Plug-in Types

Directive Description Example of use
entryfetch Declares an entry fetch plug-in, which is called by the server after retrieving an entry from the default backend database. If you encrypt data with an entry store plug-in function before saving the data to the database, you can define an entry_fetch function that decrypts data after reading it from the database.
entrystore Declares an entry store plug-in, which is called by the server before saving an entry to the default backend database. (If you are writing your own database plug-in, you do not need to use this plug-in.) You can define an entry_store function to encrypt data before saving the data to the database.
extendedop Declares an extended operation plug-in, which is called by the server when receiving a request for an extended operation from a client. Three common server operations use extended operation plug-ins:
  • StartTLS (start_tls_extop.c)
  • Password Change (passwd_extop.c)
  • Replication (plugins/replication/)
matchingRule Declares a matching rule plug-in, which is called by the server when receiving a search request with an extensible matching search filter from a client. This type of plug-in is also called by the server when indexing attributes for the backend database.
postoperation Declares a post-operation/data notification plug-in, which is called by the server after performing an LDAP operation. You can define a data_notification function to send notification to the administrator if certain data has changed.
preoperation Declares a pre-operation/data validation plug-in, which is called by the server before performing an LDAP operation. You can define a data_validation function to check new entries before they are added to the directory.
syntax Declares a syntax plug-in, which is called by the server when getting a list of possible candidates for a search, when determining how to compare values in searches, and when adding or deleting values from certain attribute indexes. You can define a function that specifies how the equals comparison works for case-insensitive strings.
object Declares an object plug-in. Object plug-ins can install SLAPI_PLUGIN_START_FN, SLAPI_PLUGIN_CLOSE_FN, and SLAPI_PLUGIN_POSTSTART_FN functions. They can also use the slapi_register_plugin() call to register any other kind of plug-in. Object plug-ins are typically used to simplify configuration of a group of related plug-ins (one entry under cn=config instead of many). You can use this plug-in type when the plug-in does not fit in any of the other types listed in this table. For example, if the plug-in does performs more than one operation, then you should use this directive. This type of plug-in will typically register the types of operations it wants to handle using the internal API.
pwdstoragescheme This defines a new hashing scheme for passwords. This kind of plug-in can be used to add support for hashing or encrypting passwords with a method that is not otherwise supported in Directory Server.

3.2. Loading the Plug-in Configuration File

After you have written the plug-in configuration file, you need to load it into the /etc/dirsrv/slapd-instance_name/dse.ldif file. You can do this either by using an LDAP utility, such as ldapmodify, or by editing the file directly. If you choose to edit the file directly, be sure to shut down the Directory Server first.
The following is an example of an LDAP command that loads the plug-in defined in the configuration file
example-plugin.ldif: ldapmodify -h my_host -p 389 -a -D cn= Directory Manager -W -f example-plugin.ldif
After the plug-in configuration has been loaded, restart the Directory Server in order to make calls to the plug-in. The Directory Server Console can restart the server from the Tasks tab, or run the following from the command line:
service dirsrv restart

3.3. Passing Extra Arguments to Plug-ins

The standard method for configuring plug-ins is to provide configuration parameters as attributes and values in the plug-in entry in the dse.ldif file. All plug-ins use the extensibleObject object class, so any custom attribute can be added to that object class in the schema. A better alternative is to define a custom auxiliary object class which contains the custom plug-in configuration attributes.
Use the plug-in start function (registered in the initialization function with slapi_pblock_set() using SLAPI_PLUGIN_START_FN) to use the custom configuration. One of the pblock parameters passed to the start function is the plug-in entry, as the SLAPI_ADD_TARGET parameter. The slapi_entry_attr_* family of functions can be used to get and use these values.
Plug-ins can be dynamically configured at run-time by registering DSE callbacks for the plug-in entry with slapi_config_register_callback().

Example 3.2. Extended Operation Plug-in

dn: cn=Test Extended Op,cn=plugins,cn=config
objectClass: top
objectClass: nsSlapdPlugin
objectClass: extensibleObject
cn: Test ExtendedOp
nsslapd-pluginPath: libtest-plugin.so
nsslapd-pluginInitfunc: testexop_init
nsslapd-pluginType: extendedop
nsslapd-pluginEnabled: on
nsslapd-plugin-depends-on-type: database
nsslapd-pluginId: test-extendedop
nsslapd-pluginarg0: 1.2.3.4

Example 3.3. MemberOf Plug-in

dn: cn=MemberOf Plugin,cn=plugins,cn=config 
objectClass: top 
objectClass: nsSlapdPlugin 
objectClass: extensibleObject 
cn: MemberOf Plugin 
nsslapd-pluginPath: libmemberof-plugin
nsslapd-pluginInitfunc: memberof_postop_init 
nsslapd-pluginType: postoperation 
nsslapd-pluginEnabled: off 
nsslapd-plugin-depends-on-type: database 
memberofgroupattr: member 
memberofattr: memberOf 
nsslapd-pluginId: memberof 
nsslapd-pluginVersion: 1.1.4 
nsslapd-pluginVendor: Fedora Project 
nsslapd-pluginDescription: memberof plugin
This method allows for a much more descriptive configuration, which is easier to maintain. The attributes beginning with pam are specific to the plug-in and used for its configuration. The plug-in entry is provided to the plug-in start function as a Slapi_Entry * in the SLAPI_ADD_TARGET pblock parameter. Use the slapi_entry_attr_* family of functions to get the configuration values from that entry.
For additional information, code samples are available from the 389 Directory Server repositories at http://git.fedorahosted.org/cgit/389/ds.git/tree/ldap/servers/plugins and http://git.fedorahosted.org/cgit/389/ds.git/tree/ldap/servers/slapd/test-plugins. The plug-in samples are in the install_directory//ldapserver/ldap/servers/slapd directory.

3.4. Setting the Log Level of the Server

If the functions call the slapi_log_error() function to write messages to the error log, you need to make sure that the Directory Server is configured to log messages with the severity level that you have specified. The available severity levels are fully documented in Part IV, “Function Reference”.
For example, suppose you call this function in the plug-in:
slapi_log_error( SLAPI_LOG_PLUGIN, "searchdn_preop_init", ”Plug-in successfully registered.\n“ );
You need to make sure that the Directory Server is configured to log messages with the severity level SLAPI_LOG_PLUGIN. Error logging is controlled with the nsslapd-errorlog-level attribute in cn=config.

Chapter 4. An Example Plug-in

This chapter provides an example of a pre-operation Red Hat Directory Server plug-in that you can compile and run. It provides both the source code and a makefile that you can use to build the plug-in.
Even though you may not understand all of the functionality contained in the example, all of the necessary concepts are explained in detail in the chapters that follow.
The example shows how to create a pre-operation plug-in for the LDAP search operation. That is, the Directory Server will process the registered plug-in functions before it processes each LDAP search operation. The example contains two primary functions:
  • The test_preop_search() function logs information about the search, including the base DN of the search, the search scope, and the type of filter used.
  • The test_preop_init() function is the initialization function that registers test_preop_search() as a SLAPI_PLUGIN_PRE_SEARCH_FN pre-operation plug-in function for LDAP search operations.
These functions illustrate the data in the parameter block that is available to your function. You can get and manipulate the parameter block data by calling various front-end API functions.

4.1. Writing the Plug-in Example

Example 4.1, “Sample Pre-Operation Search and Initialization Functions” includes the sample pre-operation search function and the sample initialization function.

Example 4.1. Sample Pre-Operation Search and Initialization Functions

#include <stdio.h>
#include <string.h>
#include "dirsrv/slapi-plugin.h"

/* function prototypes */

int test_preop_init( Slapi_PBlock *pb );
int test_preop_search( Slapi_PBlock *pb );

/* Description of the plug-in */

Slapi_PluginDesc srchpdesc = { "test-search", "example.com", "0.5","sample pre-operation search plugin" };

/* Initialization function

This function registers your plug-in function as a
pre-operation search function in the Directory Server.
You need to specify this initialization function in the
server configuration file so that the server calls
this initialization function on startup. */

#ifdef _WIN32

__declspec(dllexport)

#endif

int test_preop_init( Slapi_PBlock *pb ) 
{
  /* Specify the version of the plug-in ( "03" in this release ) */
  
  if (slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_03 ) != 0 ||
  
  /* Specify the description of the plug-in */
  
  slapi_pblock_set( pb,SLAPI_PLUGIN_DESCRIPTION, (void *)&srchpdesc ) != 0 ||
  
  /* Set test_preop_search() as the function to call before
  executing LDAP search operations. */
  
  slapi_pblock_set( pb, SLAPI_PLUGIN_PRE_SEARCH_FN, (void *) test_preop_search ) !=0 ) {
  
    /* Log an error message and return -1 if a problem occurred*/
    
    slapi_log_error( SLAPI_LOG_PLUGIN, "test_preop_init" ,"Error registering the plug-in.\n" );
    return( -1 );
  }
  
  /* If successful, log a message and return 0 */
  
  slapi_log_error( SLAPI_LOG_PLUGIN, "test_preop_init" ,"Plug-in successfully registered.\n" );
  return( 0 );
}

/* Pre-operation plug-in function for LDAP search operations
This function is called by the server before processing an LDAP
search operation. The function gets data about the search request
from the parameter block and prints the data to the error log. */

int test_preop_search( Slapi_PBlock *pb )
{

  char *base, *filter_str, *attr_type, *substr_init, *substr_final;
  char **substr_any;
  int scope, deref, filter_type, i;
  Slapi_Filter *filter;
  struct berval *bval;
  
  /* Log a message to indicate when the plug-in function starts */
  
  slapi_log_error( SLAPI_LOG_PLUGIN, "test_preop_search" ,"*** PREOPERATION SEARCH PLUGIN ***\n" );
  
  /* Get and log the base DN of the search criteria */
  
  if ( slapi_pblock_get( pb, SLAPI_SEARCH_TARGET, &base ) == 0 ) {
    slapi_log_error( SLAPI_LOG_PLUGIN, "SLAPI_SEARCH_TARGET" ,"%s\n" , base );
  } else {
    slapi_log_error( SLAPI_LOG_FATAL, .test_preop_search., .Error: could not get search base\n. );
  }
  
  /* Get and log the search scope */
  
  if ( slapi_pblock_get( pb, SLAPI_SEARCH_SCOPE, &scope ) == 0 ) {
    switch( scope ) {
      case LDAP_SCOPE_BASE:
        slapi_log_error( SLAPI_LOG_PLUGIN, "SLAPI_SEARCH_SCOPE" ,"LDAP_SCOPE_BASE\n" );
        break;
      
      case LDAP_SCOPE_ONELEVEL:
        slapi_log_error( SLAPI_LOG_PLUGIN, "SLAPI_SEARCH_SCOPE" ,"LDAP_SCOPE_ONELEVEL\n" );
        break;
      
      case LDAP_SCOPE_SUBTREE:
        slapi_log_error( SLAPI_LOG_PLUGIN, "SLAPI_SEARCH_SCOPE" ,"LDAP_SCOPE_SUBTREE\n" );
        break;
      
      default:
        slapi_log_error( SLAPI_LOG_PLUGIN, "SLAPI_SEARCH_SCOPE" ,"unknown value specified: %d\n" , scope );
        break;
    }
  } else {
    slapi_log_error( SLAPI_LOG_FATAL, .test_preop_search., .Error: could not get search scope\n. );
  }

/* Get and log the alias dereferencing setting */

if ( slapi_pblock_get( pb, SLAPI_SEARCH_DEREF, &deref ) == 0 ) {
  switch( deref ) {
    case LDAP_DEREF_NEVER:
      slapi_log_error( SLAPI_LOG_PLUGIN, "SLAPI_SEARCH_DEREF" ,"LDAP_DEREF_NEVER\n" );
      break;
    
    case LDAP_DEREF_SEARCHING:
      slapi_log_error( SLAPI_LOG_PLUGIN, "SLAPI_SEARCH_DEREF" ,"LDAP_DEREF_SEARCHING\n" );
      break;
    
    case LDAP_DEREF_FINDING:
      slapi_log_error( SLAPI_LOG_PLUGIN, "SLAPI_SEARCH_DEREF" ,"LDAP_DEREF_FINDING\n" );
      break;
    
    case LDAP_DEREF_ALWAYS:
      slapi_log_error( SLAPI_LOG_PLUGIN, "SLAPI_SEARCH_DEREF" ,"LDAP_DEREF_ALWAYS\n" );
      break;
    
    default:
      slapi_log_error( SLAPI_LOG_PLUGIN, "SLAPI_SEARCH_DEREF" ,"unknown value specified: %d\n" , deref );
      break;
  }
} else {
    slapi_log_error( SLAPI_LOG_FATAL, "test_preop_search", "Error: could not get search alias deref\n" );
}

/* Get and log the search filter information */

if (slapi_pblock_get(pb,SLAPI_SEARCH_FILTER, &filter)==0 ) {

  /* Get and log the filter type */
  
  filter_type = slapi_filter_get_choice( filter );
  switch( filter_type ) {
  
    case LDAP_FILTER_AND:
    
    case LDAP_FILTER_OR:
    
    case LDAP_FILTER_NOT:
    
      slapi_log_error( SLAPI_LOG_PLUGIN, "SLAPI_SEARCH_FILTER" ,
      "Complex search filter. See value of
      SLAPI_SEARCH_STRFILTER.\n" );
      break;
    
    case LDAP_FILTER_EQUALITY:
      slapi_log_error( SLAPI_LOG_PLUGIN, "SLAPI_SEARCH_FILTER" ,"LDAP_FILTER_EQUALITY\n" );
      break;
    
    case LDAP_FILTER_GE:
      slapi_log_error( SLAPI_LOG_PLUGIN, "SLAPI_SEARCH_FILTER" ,"LDAP_FILTER_GE\n" );
      break;
    
    case LDAP_FILTER_LE:
      slapi_log_error(SLAPI_LOG_PLUGIN, "SLAPI_SEARCH_FILTER" ,"LDAP_FILTER_LE\n" );
      break;
    
    case LDAP_FILTER_APPROX:
      slapi_log_error( SLAPI_LOG_PLUGIN, "SLAPI_SEARCH_FILTER" ,"LDAP_FILTER_APPROX\n" );
      break;
    
    case LDAP_FILTER_SUBSTRINGS:
      slapi_log_error( SLAPI_LOG_PLUGIN, "SLAPI_SEARCH_FILTER" ,"LDAP_FILTER_SUBSTRINGS\n" );
    
      /* For substring filters, get and log the attribute type and
      the substrings in the filter */
    
      slapi_filter_get_subfilt( filter, &attr_type, &substr_init, &substr_any, &substr_final );
      if ( attr_type != NULL )
        slapi_log_error( SLAPI_LOG_PLUGIN, "\tAttribute type" ,"%s\n" ,attr_type );
    
      if ( substr_init != NULL )
        slapi_log_error( SLAPI_LOG_PLUGIN, "\tInitial substring" ,"%s\n" , substr_init );
    
      if ( substr_any != NULL ) {
        for ( i = 0; substr_any[i] != NULL; i++ ) {
          slapi_log_error( SLAPI_LOG_PLUGIN, "\tSubstring" ,"# %d: %s\n" , i, substr_any[i] );
        }
      }
    
      if (substr_final != NULL )
        slapi_log_error( SLAPI_LOG_PLUGIN, "\tFinal substring" ,"%s\n" , substr_final );
      break;
    
    case LDAP_FILTER_PRESENT:
      slapi_log_error( SLAPI_LOG_PLUGIN, "SLAPI_SEARCH_FILTER" ,"LDAP_FILTER_PRESENT\n" );
    
      /* For presence filters, get and log the attribute type */
    
      slapi_filter_get_type( filter, &attr_type );
    
      if ( attr_type != NULL )
        slapi_log_error( SLAPI_LOG_PLUGIN, "\tSearch for presence of attr" ,"%s\n" , attr_type );
      break;
    
    case LDAP_FILTER_EXTENDED:
      slapi_log_error( SLAPI_LOG_PLUGIN, "SLAPI_SEARCH_FILTER" ,"LDAP_FILTER_EXTENDED\n" );
      break;
    
    default:
      slapi_log_error( SLAPI_LOG_PLUGIN, "SLAPI_SEARCH_FILTER" , "Unknown filter type:
      slapi_filter_get_choice returned %d\n", filter_type );
      break; 
  }
}else {
    slapi_log_error( SLAPI_LOG_FATAL, "test_preop_search", "Error: could not get search filter\n" );
}

  /* For comparison filters, get and log the attribute type */
  
  if ( filter_type == LDAP_FILTER_EQUALITY || LDAP_FILTER_GE ||
  LDAP_FILTER_LE || LDAP_FILTER_APPROX ) {
    slapi_filter_get_ava( filter, &attr_type, &bval );
    
    if ( ( attr_type != NULL ) && ( bval->bv_val != NULL ) ) {
      slapi_log_error( SLAPI_LOG_PLUGIN, "\tAttribute type" ,"%s\n" , attr_type );
      slapi_log_error( SLAPI_LOG_PLUGIN, "\tAttribute value" ,"%s\n" , bval->bv_val );
    }
  }
  
  /* Get and log the string representation of the filter */
  
  if ( slapi_pblock_get(pb, SLAPI_SEARCH_STRFILTER, &filter_str) == 0 )
    slapi_log_error( SLAPI_LOG_PLUGIN, "SLAPI_SEARCH_STRFILTER" ,"%s\n" , filter_str );
  slapi_log_error( SLAPI_LOG_PLUGIN, "test_preop_search" ,"*** DONE ***\n\n" );
  return( 0 );
}

4.2. Compiling the Plug-in Example

The makefile in Example 4.2, “Makefile” can compile the example.
This example assumes that the source code is stored in srchxmpl.c and that the plug-in being compiled is srchxmpl.so. Additionally, the 389-ds-base-devel package must have been installed or the header file, slapi-plugin.h, is in /usr/include/dirsrv specified in the include path. Otherwise, specify -I /path/to/slapi-plugin.h in the CFLAGS directive.

Example 4.2. Makefile

# Makefile for Directory Server plug-in examples
#
CC = gcc
LD = gcc
CFLAGS = -fPIC
LDFLAGS = -shared
OBJS = srchxmpl.o
all: srchxmpl.so
srchxmpl.so: $(OBJS)
	$(LD) $(LDFLAGS) -o $@ $(OBJS)
.c.o:
	$(CC) $(CFLAGS) -c $<
clean:
	-rm -f $(OBJS) srchxmpl.so

4.3. Registering the Plug-in

To register this example plug-in, you need to:
  1. Create an LDIF configuration file in an ASCII text editor. See Section 3.1, “Creating a Plug-in Configuration File”.
  2. Load the plug-in configuration file. See Section 3.2, “Loading the Plug-in Configuration File”.
  3. Shut down the Directory Server.
  4. Restart the Directory Server.
When you restart the Directory Server, it will read the entries in the dse.ldif file, which contains the entry for your new plug-in. It is a good idea to check the plug-ins list in the Directory Server Console to ensure that your plug-in loaded.

4.4. Running the Plug-in

After compiling the plug-in and registering it with the Directory Server, you can make calls that are processed by the plug-in functions.
The first step is to restart the Directory Server and check the error log to see that the plug-in is properly registered. You should see the following line in the error log:
Error log messsage here!
Verify that the plug-ins log level is selected. Error logging is controlled with the nsslapd-errorlog-level attribute in cn=config. For the plug-ins log level, set this value to 65536 or set an OR for the current value to 65536. (The sample source code logs messages to the error log with the plug-ins severity level.)
If the plug-in is properly registered, you can then perform a few searches against the directory. The pre-operation search plug-in function should write data about each search to the error log.

Part II. Writing Functions and Plug-ins

Chapter 5. Frontend API Functions

The Red Hat Directory Server (Directory Server) provides some general-purpose, frontend API functions that allow you to work with the entries in the Directory Server. This chapter explains how to use the frontend API functions to accomplish various tasks; you can call these functions in your plug-in to interact with the client (for example, to send results or result codes), log messages, and work with entries, attributes, and filters. While all of the functions described here must be used in conjunction with other API functions, understanding how these functions work will help you understand how to program other plug-in API functions.
The frontend functions are declared in the slapi-plugin.h header file.

5.1. Logging Messages

To write an error message to the error log, call the slapi_log_error() function. For example, the following function call writes a message in the error log:
slapi_log_error( SLAPI_LOG_PLUGIN, "searchdn_preop_search", "*** PREOPERATION SEARCH PLUGIN ***\n");
This call will create the following message in the error log:
[01/Oct/1997:02:24:18 -0700] searchdn_preop_search  *** PREOPERATION SEARCH PLUGIN ***
Make sure that the Directory Server is configured to log messages that have the severity that you specify (for example, SLAPI_LOG_PLUGIN). For more information, see Section 3.4, “Setting the Log Level of the Server”. The slapi_log_error() function allows additional parameters to be added to the function and to format the output, similar to the standard printf() function. This provides a way to add custom parameters and data to the log output.
Some debugging output is expensive to calculate, so check if a certain log level is set before doing additional processing. The slapi_is_loglevel_set() function can determine if the log level is set. For example:
 if (slapi_loglevel_is_set(SLAPI_LOG_PLUGIN)) {
    do some expensive processing for debugging purposes....
    slapi_log_error(SLAPI_LOG_PLUGIN, .my plugin., ... some data...);
  }

5.2. Adding Notes to Access Log Entries

When the backend database processes a search operation, it attempts to use indexes to narrow down the list of candidates matching the search criteria. If the back-end is unable to use indexes, it appends the following string to the access log entry for the search: notes="U"
This note indicates that an unindexed search was performed.
If you are writing your own backend database search function, you can append this note to access log entries by setting the SLAPI_OPERATION_NOTES parameter to the flag SLAPI_OP_NOTE_UNINDEXED. This parameter identifies any notes that need to be appended to access log entries. Currently, SLAPI_OP_NOTE_UNINDEXED is the only value that you can set for this parameter. In future releases, additional flags will be defined. You will be able to use bitwise OR combinations of flags to specify different combinations of notes.
The server appends these notes and writes out the access log entries whenever sending a result or search entry back to the client.

5.3. Sending Data to the Client

Sometimes you might need to communicate various information directly to the client. This could occur in the following situations:
  • If you need to send a result code to the client (for example, to report an error or a successful result to an LDAP operation), call the slapi_send_ldap_result() function.
  • If you are fulfilling a search request and need to send matching entries to the client, call the slapi_send_ldap_search_entry() function for each entry.
  • To refer the LDAP request to a different LDAP server, call the slapi_send_ldap_referral() function.
For example, the following statement sends an LDAP_SUCCESS status code back to the client:
slapi_send_ldap_result( pb, LDAP_SUCCESS, NULL, "The operation was processed successfully.\n", 0, NULL );

Important

Ensure that you send only one result per operation to the client.

5.4. Determining If an Operation Was Abandoned

At any point in time, the client can choose to abandon an LDAP operation. When writing database functions, remember that you should periodically check to see if the operation has been abandoned.
To determine if an operation has been abandoned, call slapi_op_abandoned(). For example:
if ( slapi_op_abandoned( pb ) ) {
	slapi_log_error( SLAPI_LOG_PLUGIN, "my_function", "The operation was abandoned.\n" );
	return 1;
}

5.5. Working with Entries, Attributes, and Values

In certain situations, you will need to pass directory entries between the frontend and the client. For example, it you create a custom add function, the frontend passes an entry to your function in the parameter block. When you perform a search operation, you return each matching search entry to the client.
When working with entries, use the Slapi_Entry data type to get attribute value pairs. The frontend routines listed in Table 5.1, “Frontend Functions for Manipulating Entries and Attributes” are designed to help you manipulate entries passed in parameter blocks. These functions are described in more detail in the following sections.

Table 5.1. Frontend Functions for Manipulating Entries and Attributes

Frontend Function Description
Allocate memory for a new entry.
Initialize the entry created with slapi_entry_alloc().

Important

This must be done before any other operation can occur on the entry. Otherwise, severe memory errors may occur.
Copy an entry.
Free an unused entry from memory.
Convert an entry to an LDIF string representation and vice versa.
Get or set the DN for an entry.
Verify that an entry complies with the schema.
Get the attributes of an entry.
Find the values for a specified attribute.
Merge an attribute and its values into an entry.
Add values to an attribute in an entry.

5.5.1. Creating a New Entry

In some situations, you might need to create a new entry. You can create a new entry in two ways:
  • By allocating memory for a new entry.
    To allocate memory for a new entry, call the slapi_entry_alloc() function. This function returns a pointer to a new entry of the opaque datatype Section 14.22, “Slapi_Entry”. Then, call the function slapi_entry_init() to initialize the entry for use with the other slapi functions. Once you create and initialize a new entry, you should call other frontend routines to set the DN and attributes of the entry.

    Note

    Failing to call slapi_entry_init() after slapi_entry_alloc() may cause severe memory problems.
  • By copying an existing entry.
    To make a copy of an existing entry, call the slapi_entry_dup() routine. This function returns a pointer to a new entry of the data type Slapi_Entry that contains the copied data.
When you are finished using the entry, you should free it from memory by calling the slapi_entry_free() function.

5.5.2. Converting Between Entries and Strings

Entries can be stored in LDIF files. When stored in these files, entries are converted into a string representation. The following format is the LDIF string representation for a directory entry:
dn:[:]dn\n
[<attr>:[:]<value>\n]
[<attr>:[:]<value>\n]
[<spacecontinuedvalue>\n]*
...
To continue the specification of a value on additional lines (that is, if the value wraps to another line), use a single space (the ASCII 32 character) at the beginning of subsequent lines. For example:
dn: cn=Jane Doe
 inski, ou=Accoun
 ting, dc=ex
 ample 
 dc=com
Refer to the Red Hat Directory Server Administrator's Guide for details on DN syntax.
If a double-colon is used after a data type, it indicates that the value after the double-colon is encoded as a base-64 string. Data is sometimes encoded as a base-64 string. For example, it might be encoded this way if the value contains a non-printing character or newline.
You can use the following functions to convert between the LDIF string representation of an entry and its Slapi_Entry data type:
  • To convert an entry from the Slapi_Entry data type to its LDIF string representation, call the slapi_entry2str() and slapi_entry2str_with_options() functions.
    This function returns the LDIF string representation of the entry, or NULL if an error occurs. When the string is no longer required, free it from memory by calling the slapi_ch_free_string()* function.
  • To convert an LDIF string representation back to an entry of the data type Slapi_Entry, call the slapi_str2entry() function.
    This function returns an entry of the data type Slapi_Entry*. If an error occurred during the conversion process, the function returns NULL instead.
When you are finished working with the entry, call the slapi_entry_free() function.

Note

Calling the slapi_str2entry() function modifies the value of the string argument passed into the function (not a copy). To use the string representation of the entry still, make a copy of the string using slapi_ch_strdup() before calling this function. Then, call slapi_ch_free_string() to free the copied string after use.

5.5.3. Miscellaneous Operations

5.5.3.1. Getting and Setting the DN of an Entry

You can call the following two frontend routines to get and set the DN for an entry:

5.5.3.2. Verifying Compliance with the Schema

Before you add or modify an entry in the database, you may want to verify that the new or changed entry still complies with the database schema.
To verify that an entry complies with the schema, call the slapi_entry_schema_check() function.

5.5.3.3. Getting the Attributes and Values of an Entry

You can use either of the following methods to obtain the attributes and values of an entry:
  • Iterate through the attributes of the entry, testing each one to determine if it is the required attribute.
  • Use the slapi_entry_attr_find() function to determine if an entry has a specific attribute.
After you have found the required attribute, use the slapi_attr_value_find() function to return the value of that attribute, or use slapi_attr_value_first() and slapi_attr_value_next() to iterate through all of the values of a multi-valued attribute.
5.5.3.3.1.  Iterating through the Attributes in an Entry
To iterate through the attributes associated with an entry, call the slapi_entry_first_attr() function to get the first attribute of the entry. This function returns a pointer to the first attribute in the entry. You can use the pointer to the attribute to determine if it is the attribute that you want.
To retrieve the subsequent parameters in the entry, call slapi_entry_next_attr(), and pass it the pointer to the current parameter in the cookie parameter of the function. The slapi_entry_next_attr() function returns a pointer to the current parameter in the same fashion as the slapi_entry_first_attr() function.
After finding the required attribute, it is possible to retrieve its value using slapi_attr_value_find() or using slapi_attr_value_first() and slapi_attr_value_next() to iterate through all of the values of a multi-valued attribute.
5.5.3.3.2.  Finding a Specific Attribute in an Entry
To determine if an entry contains a specific attribute, call the slapi_entry_attr_find() function. This function returns 0 if the entry contains the attribute, -1 if it does not.

5.5.3.4. Adding and Removing Values

You can call frontend routines to add or remove attributes and values in an entry. The frontend provides the following functionality:
There are many convenience functions provided to get and set values of attributes in an entry, beginning with slapi_entry_attr_get* and slapi_entry_attr_set*, respectively. These functions allow you to get and set specific values in a Slapi_Entry. Because they are convenience functions, there are some limitations about their use.

Example 5.1. Get Functions

char **slapi_entry_attr_get_charray(const Slapi_Entry* e, const char *type);
char *slapi_entry_attr_get_charptr(const Slapi_Entry* e, const char *type);
int slapi_entry_attr_get_int(const Slapi_Entry* e, const char *type);
unsigned int slapi_entry_attr_get_uint(const Slapi_Entry* e, const char *type);
long slapi_entry_attr_get_long( const Slapi_Entry* e, const char *type);
unsigned long slapi_entry_attr_get_ulong( const Slapi_Entry* e, const char *type);
long long slapi_entry_attr_get_longlong( const Slapi_Entry* e, const char *type);
unsigned long long slapi_entry_attr_get_ulonglong( const Slapi_Entry* e, const char *type);
PRBool slapi_entry_attr_get_bool( const Slapi_Entry* e, const char *type);
The type parameter is the name of the attribute.
If the attribute does not exist in the entry, the get function return a 0 or NULL value. Some attributes may actually exist and have a 0 value, so to verify that an attribute exists before getting the value, use slapi_entry_attr_find() first.
These functions return only the first value of an attribute. For multi-valued attributes, use a function to get the Slapi_Attr*, then iterate through the values using the slapi_attr_first_value() and slapi_attr_next_value() functions.
Values are usually stored as strings. The functions that return integral values (such as get_int and get_uint) use atoi(3) to get the int values, atol(3) to get the long values, and strtoll(3) to get the longlong values. Check the platform documentation for these functions for information about how these functions deal with non-integral values. They usually return a 0 if the value could not be converted to the specified type. To continue these functions, ensure the value is of the correct type.
slapi_entry_attr_get_charray() returns either NULL or allocated memory that must be freed with slapi_ch_array_free(). The last element of the array is (char *)NULL, so you can iterate through the values looking for this as the termnator. slapi_entry_attr_get_charptr() returns either NULL or allocated memory that must be freed with slapi_ch_free_string().
slapi_entry_attr_get_bool() returns a PR_TRUE if the value is present and is equivalent to true, yes, or a non-zero numeric value. It returns PR_FALSE if the value is absent, empty, or any of the values false, no, or a numeric 0 value. String comparisons are case-insensitive, so TRUE is the same as True or true.

Example 5.2. Set Functions

void slapi_entry_attr_set_charptr(Slapi_Entry* e, const char *type, const char *value);
void slapi_entry_attr_set_int( Slapi_Entry* e, const char *type, int l);
void slapi_entry_attr_set_uint( Slapi_Entry* e, const char *type, unsigned int l);
void slapi_entry_attr_set_long(Slapi_Entry* e, const char *type, long l);
void slapi_entry_attr_set_ulong(Slapi_Entry* e, const char *type, unsigned long l);
The type parameter is the name of the attribute. If the attribute does not exist in the entry, the set function creates it and sets the value. If the attribute exists in the entry, the set function will replace all values with the new specified value. To add values without replacing, use slapi_entry_add_values_sv().
slapi_entry_attr_set_charptr() makes a copy of the specified value, so this function is ok to use with a string constant or other non-writable string value. Passing a value of NULL deletes the specified attribute from the entry, just like calling slapi_entry_attr_delete(Slapi_Entry *, const char *type).
There is no slapi_entry_attr_set_charray() nor slapi_entry_attr_set_bool() function. For the former function, use a Slapi_Attr* or Slapi_Value* API function to add the multiple values. For the latter, use slapi_entry_attr_set_charptr() or slapi_entry_attr_set_int() to set the value to the true or false value.

5.6. Working with DNs and RDNs

In certain situations, the frontend passes DNs to the backend through the parameter block. For example, when calling the add function, the parameter block includes a parameter that specifies the DN of the new entry to be added.
If you need to manipulate DNs within parameter blocks, you can call the following frontend routines:

Table 5.2. Frontend Functions for Manipulating DNs

Function Description
slapi_dn_isroot() Determines if a DN is the root DN (the DN of the privileged superuser).
Gets a copy of the parent DN.
slapi_sdn_issuffix() Checks if a Slapi_DN structure is the child of another suffix.
slapi_be_issuffix() Determines if a DN is a suffix served by one of the server's backends.
slapi_sdn_get_ndn() Normalizes a DN.
slapi_dn_normalize_case() Normalizes a DN and converts all characters to lowercase.

5.6.1. Determining If a DN Is the Root DN

To determine if a DN is the root DN, call slapi_dn_isroot(). This function returns 1 if the specified DN is the root DN of the local database. It returns 0 if the DN is not the root DN.

5.6.2. Working with DN Suffixes

A suffix of a DN identifies a subtree in the directory tree where the DN is located. For example, consider the following DN:
cn=Babs Jensen,ou=Product Development,l=US, dc=example,dc=com
In this case, one of the suffixes is:
l=US, dc=example,dc=com
This suffix indicates that the Babs Jensen entry is located in the Example Corporation subtree in the directory tree.
To determine if a value is a suffix for a DN, call slapi_sdn_issuffix(). To determine if a DN is one of the suffixes served by the backend, call the slapi_be_issuffix() function.
For more information on suffixes and backend configuration, see the Administrator's Guide.

5.6.3. Getting the Parent DN of a DN

To get a copy of the parent DN for a DN, call either the slapi_sdn_get_parent() or the slapi_sdn_get_backend_parent() function.
These functions return the parent DN of dn. If dn is a suffix served by the backend, slapi_sdn_get_backend_parent() returns NULL.
When you are finished working with the parent DN, you should free it from memory by calling slapi_ch_free_string().

5.6.4. Normalizing a DN

You can use the following frontend functions to normalize and convert the case of a DN:

Note

These functions operate on the actual DN specified in the argument, not a copy of the DN. If you want to modify a copy of the DN, call slapi_ch_strdup() to make a copy of the DN.
To compare DNs (for example, to search the database for a particular DN), use the slapi_sdn_compare() function instead of normalizing and comparing the DNs using string functions.

5.7. Working with Search Filters

When a client requests an LDAP search operation, the frontend passes the search filter to the backend as part of the parameter block. The filter is passed through the SLAPI_SEARCH_FILTER parameter. A string representation of the filter is also available in the SLAPI_SEARCH_STRFILTER parameter.
To manipulate search filters, call the following frontend routines:

Table 5.3. Frontend Functions for Manipulating Filters

Function Description
slapi_filter_test() Determine if an entry matches a filter's criteria.
slapi_filter_get_choice() Get the filter type.
slapi_filter_get_ava() Get the attribute type and value used for comparison in an attribute-value assertion filter. (Only applicable to the following searches: LDAP_FILTER_EQUALITY, LDAP_FILTER_GE, LDAP_FILTER_LE, and LDAP_FILTER_APPROX.)
slapi_filter_get_type() Get the type of attribute that the filter is searching for. (Only applicable to LDAP_FILTER_PRESENT searches.)
slapi_filter_get_subfilt() Get the substring pattern used for the filter. (Only applicable to LDAP_FILTER_SUBSTRING searches.)
slapi_str2filter() Convert a string representation of a filter to a filter of the data type Slapi_Filter.
slapi_filter_join() Construct a new LDAP_FILTER_AND, LDAP_FILTER_OR, or LDAP_FILTER_NOT filter from other filters.
Get the components of a filter. (Only applicable to LDAP_FILTER_AND, LDAP_FILTER_OR, and LDAP_FILTER_NOT searches.)
slapi_filter_free() Free a filter from memory.

5.7.1. Determining If an Entry Matches a Filter

After retrieving a filter from the SLAPI_SEARCH_FILTER parameter of the parameter block, you can call the slapi_filter_test() function to determine if entries in your database match the filter.

5.7.2. Getting the Filter Type

To determine the type of filter that you are using, call the slapi_filter_get_choice() function. This function returns the filter type, which can be any of the following values:

Table 5.4. Types of Filters

Filter Type Description
LDAP_FILTER_AND Find entries that match all filters that are specified in this complex filter.
LDAP_FILTER_OR Find entries that match any filter specified in this complex filter.
LDAP_FILTER_NOT Find entries that do not match the specified filter.
LDAP_FILTER_EQUALITY Find entries that contain a value equal to the specified attribute value.
LDAP_FILTER_SUBSTRINGS Find entries that contain a value that matches the specified substrings.
LDAP_FILTER_GE Find entries that contain a value greater than or equal to the specified attribute value.
LDAP_FILTER_LE Find entries that contain a value less than or equal to the specified attribute value.
LDAP_FILTER_PRESENT Find entries that contain the specified attribute.
LDAP_FILTER_APPROX Find entries that contain a value approximately matching the specified attribute value.

5.7.3. Getting the Search Criteria

You can use the following functions to retrieve the search criteria specified by a search filter:

Table 5.5. Functions used to Retrieve the Search Criteria Specified by Search Filters

To retrieve the search criteria for this filter type... Use this function...
LDAP_FILTER_EQUALITY
LDAP_FILTER_GE
LDAP_FILTER_LE
LDAP_FILTER_APPROX
slapi_filter_get_ava()
LDAP_FILTER_PRESENT slapi_filter_get_type()
LDAP_FILTER_SUBSTRINGS slapi_filter_get_subfilt()
LDAP_FILTER_AND
LDAP_FILTER_OR
LDAP_FILTER_NOT
Both of these functions will return either a filter component of the complex filter or a NULL value, according to the following:
  • If slapi_list_first() returns a NULL, the complex filter is not of the type LDAP_FILTER_AND, LDAP_FILTER_OR, or LDAP_FILTER_NOT.
  • If slapi_list_next() returns a NULL, the component returned by the call is the last component in the complex filter.

Note

You do not need to free the values returned by the slapi_filter_get_ava(), slapi_filter_get_type(), and slapi_filter_get_subfilt() functions.

5.7.4. Converting a String to a Filter

A search filter can be represented by either the data type Slapi_Filter or as a string. In a parameter block for a search operation, SLAPI_SEARCH_FILTER is a filter of the data type Slapi_Filter and SLAPI_SEARCH_STRFILTER is the string representation of that filter. In general, it is easier to specify a filter as a string than it is to construct a filter from the type Slapi_Filter.
To convert the string representation of a filter into a filter of the data type Slapi_Filter, call the slapi_str2filter() function.
When you have finished working with the filter, you should free it from memory by calling the slapi_filter_free() function.

5.7.5. Creating Complex Filters by Combining Filters

AND, OR and NOT can combine different filters to create a complex filter. The slapi_filter_join() function can create these types of filters.
The slapi_filter_join() function returns the complex filter that you created. When you have finished using the complex filter, you should free it from memory by calling slapi_filter_free().
Filters of the type LDAP_FILTER_NOT can have only one component. If the filter type (ftype) is LDAP_FILTER_NOT, you must pass a NULL value for the second filter when calling slapi_filter_join().

5.8. Checking Passwords

By default, Directory Server uses the userPassword attribute to store the credentials for an entry. The server encodes the password using the scheme specified in the nsslapd-rootpwstoragescheme attribute for the Directory Manager or passwordStorageScheme attribute for other users. These attributes are defined in the cn=config entry contained in the dse.ldif file. The scheme can be any of the following:
  • CLEAR — No encryption is used, and can be defined using the clear-password-storage-scheme plug-in.
  • CRYPT — Uses the Unix crypt algorithm, and can be defined using the crypt-password-storage-scheme plug-in.
  • SHA, SHA256, SHA384, SHA512 — Uses the Secure Hashing Algorithm, and can be defined using the sha-password-storage-scheme plug-in. SHA is SHA-1, which is 140 bits. For the others, the number indicates the number of bits used by the hash.
  • SSHA, SSHA256, SSHA384, SSHA512 — Uses the Salted Secure Hashing Algorithm, and can be defined using the ssha-password-storage-scheme plug-in. SSHA is SSHA-1, which is 140 bits, including the salt. For the others, the number indicates the number of bits used by the hash, including the salt.
To determine if a given password is one of the values of the userPassword attribute, call the slapi_pw_find_sv() function. This function determines which password scheme was used to store the password and uses the appropriate comparison function to compare a given value against the encrypted values of the userPassword attribute.

Chapter 6. Writing Pre- and Post-operation Plug-ins

This chapter explains how to write functions that the Red Hat Directory Server (Directory Server) calls before and after executing an LDAP operation. These functions are called pre-operation and post-operation plug-in functions.

6.1. How Pre- and Post-operation Plug-ins Work

The Directory Server can perform the following LDAP operations: bind, unbind, search, modify, add, delete, modifyRDN, compare, and abandon.

Note

The Directory Server can also perform extended operations as defined in the LDAPv3 protocol. For information on implementing plug-in functions to execute extended operations, refer to Chapter 10, Writing Extended Operation Plug-ins.
You can configure the Directory Server to call your custom plug-in functions before and after executing any of these LDAP operations.
For example, you can write a pre-operation function that validates an entry before the server performs an LDAP add operation. An example of a post-operation plug-in function would be one that sends a notification to a user after their entry has been modified by an LDAP modify operation.
The Directory Server can call custom plug-in functions before and after performing operations, such as:
  • Sending an LDAP entry to the client.
  • Sending an LDAP result code to the client.
  • Sending an LDAP referral to the client.
Figure 6.1, “Calling Pre-operation and Post-operation Plug-in Functions” illustrates how the Directory Server front-end calls pre-operation and post-operation functions before and after executing an LDAP operation.
When processing a request, the Directory Server will call all registered pre-operation functions before it calls the backend to service the request. All pre-operation functions must return before the front-end calls the associated backend function.
Calling Pre-operation and Post-operation Plug-in Functions

Figure 6.1. Calling Pre-operation and Post-operation Plug-in Functions

6.2. Types of Pre-operation and Post-operation Functions

Pre-operation and post-operation functions are specified in a parameter block that you can set on server startup. Each function corresponds to an ID in the parameter block. In your initialization function, you can call the slapi_pblock_set() function to specify the name of your function that corresponds to the pre-operation or post-operation function. For more information on the parameter block, refer to Section 2.1.3.1, “Getting Data from the Parameter Block”.

6.2.1. Types of Pre-operation Functions

The following table lists the Directory Server pre-operation functions and their purpose.

Table 6.1. Functions Called Before the Directory Server Executes an Operation

ID in Parameter Block Description Further Information
SLAPI_PLUGIN_PRE_BIND_FN Specifies the function called before the Directory Server executes an LDAP bind operation. Section 7.2, “Processing an LDAP Bind Operation”.
SLAPI_PLUGIN_PRE_UNBIND_FN Specifies the function called before the Directory Server executes an LDAP unbind operation. Section 7.3, “Processing an LDAP Unbind Operation”.
SLAPI_PLUGIN_PRE_SEARCH_FN Specifies the function called before the Directory Server executes an LDAP search operation. Section 7.4, “Processing an LDAP Search Operation”.
SLAPI_PLUGIN_PRE_COMPARE_FN Specifies the function called before the Directory Server executes an LDAP compare operation. Section 7.5, “Processing an LDAP Compare Operation”.
SLAPI_PLUGIN_PRE_ADD_FN Specifies the function called before the Directory Server executes an LDAP add operation. Section 7.6, “Processing an LDAP Add Operation”.
SLAPI_PLUGIN_PRE_MODIFY_FN Specifies the function called before the Directory Server executes an LDAP modify operation. Section 7.7, “Processing an LDAP Modify Operation”.
SLAPI_PLUGIN_PRE_MODRDN_FN Specifies the function called before the Directory Server executes an LDAP modifyRDN operation. Section 7.8, “Processing an LDAP Modify RDN Operation”.
SLAPI_PLUGIN_PRE_DELETE_FN Specifies the function called before the Directory Server executes an LDAP delete operation. Section 7.9, “Processing an LDAP Delete Operation”.
SLAPI_PLUGIN_PRE_ABANDON_FN Specifies the function called before the Directory Server executes an LDAP abandon operation. Section 7.10, “Processing an LDAP Abandon Operation”.
SLAPI_PLUGIN_PRE_ENTRY_FN Specifies the function called before the Directory Server sends an entry to the client (for example, when you call slapi_send_ldap_search_entry(), the pre-operation entry function is called before the entry is sent to the client).  
SLAPI_PLUGIN_PRE_REFERRAL_FN Specifies the function called before the Directory Server sends a referral to the client (for example, when you call slapi_send_ldap_referral(), the pre-operation referral function is called before the referral is sent to the client).  
SLAPI_PLUGIN_PRE_RESULT_FN Specifies the function called before the Directory Server sends a result code to the client (for example, when you call slapi_send_ldap_result(), the pre-operation result function is called before the result code is sent to the client).  

6.2.2. Types of Post-operation Functions

The following table lists the Directory Server post-operation functions and their purpose.

Table 6.2. Functions Called After the Directory Server Executes an Operation

ID in Parameter Block Description Further Information
SLAPI_PLUGIN_POST_BIND_FN Specifies the function called after the Directory Server executes an LDAP bind operation. Section 7.2, “Processing an LDAP Bind Operation”.
SLAPI_PLUGIN_POST_UNBIND_FN Specifies the function called after the Directory Server executes an LDAP unbind operation. Section 7.3, “Processing an LDAP Unbind Operation”.
SLAPI_PLUGIN_POST_SEARCH_FN Specifies the function called after the Directory Server executes an LDAP search operation. Section 7.4, “Processing an LDAP Search Operation”.
SLAPI_PLUGIN_POST_COMPARE_FN Specifies the function called after the Directory Server executes an LDAP compare operation. Section 7.5, “Processing an LDAP Compare Operation”.
SLAPI_PLUGIN_POST_ADD_FN Specifies the function called after the Directory Server executes an LDAP add operation. Section 7.6, “Processing an LDAP Add Operation”.
SLAPI_PLUGIN_POST_MODIFY_FN Specifies the function called after the Directory Server executes an LDAP modify operation. Section 7.7, “Processing an LDAP Modify Operation”.
SLAPI_PLUGIN_POST_MODRDN_FN Specifies the function called after the Directory Server executes an LDAP modifyRDN operation. Section 7.8, “Processing an LDAP Modify RDN Operation”.
SLAPI_PLUGIN_POST_DELETE_FN Specifies the function called after the Directory Server executes an LDAP delete operation. Section 7.9, “Processing an LDAP Delete Operation”.
SLAPI_PLUGIN_POST_ABANDON_FN Specifies the function called after the Directory Server executes an LDAP abandon operation. Section 7.10, “Processing an LDAP Abandon Operation”.
SLAPI_PLUGIN_POST_ENTRY_FN Specifies the function called after the Directory Server sends an entry to the client (for example, when you call slapi_send_ldap_search_entry(), the post-operation entry function is called after the entry is sent to the client).  
SLAPI_PLUGIN_POST_REFERRAL_FN Specifies the function called after the Directory Server sends a referral to the client (for example, when you call slapi_send_ldap_referral(), the post-operation referral function is called after the referral is sent to the client).  
SLAPI_PLUGIN_POST_RESULT_FN Specifies the function called after the Directory Server sends a result code to the client (for example, when you call slapi_send_ldap_result(), the post-operation result function is called after the result code is sent to the client).  

6.3. Using Plug-in Configuration Information in Preop Plug-ins

A plug-in may need to access its configuration data to use as part of the initialization function. For example, a plug-in may specify a specific port to use to connect to the Directory Server for some operation, and that port number is set in the plug-in's configuration entry.
However, since the plug-in is not initialized yet, there is no SLAPI_TARGET_DN set yet. The plug-in can retrieve its own configuration using the SLAPI_PLUGIN_CONFIG_ENTRY pblock parameter.
int
my_plugin_init(Slapi_PBlock *pb)
{
	Slapi_Entry *my_config_entry = NULL;
	slapi_pblock_get(pb, SLAPI_PLUGIN_CONFIG_ENTRY, &my_config_entry);
The plug-in must not free the Slapi_Entry* returned with SLAPI_PLUGIN_CONFIG_ENTRY, and any changes made to this entry may be lost or ignored. Rhe Slapi_Entry* structure should be read-only and used only to get plug-in configuration parameters as attributes of the entry.
Use the internal slapi_modify_internal* SLAPI functions to modify the returned entry.

6.4. Registering Pre- and Post-operation Functions

To register your pre-operation and post-operation plug-in functions, you need to write an initialization function and then configure the server to load your plug-in. For details, follow the procedures outlined in Section 2.2, “Writing Plug-in Initialization Functions”, and Chapter 3, Configuring Plug-ins.

Chapter 7. Defining Functions for LDAP Operations

This chapter explains how to write pre-operation and post-operation functions for specific LDAP operations. In general, the functions outlined here use a parameter block to pass information between the plug-in and the Red Hat Directory Server. Because of this, these plug-in functions will pass a single argument, a parameter block defined by the data type Slapi_PBlock. Refer to Section 2.1.2, “Passing Data with Parameter Blocks” for more information.

7.1. Specifying Start and Close Functions

For each pre-operation and post-operation plug-in, you can specify a function to be called after the server starts and before the server is shut down.
For example, the plug-in may need some context information to pass to all of the plug-in callback functions. Then, create the context in the start function and store it in the SLAPI_PLUGIN_PRIVATE slot to use throughout the plug-in. Any resources (free()) and any memory allocated in the start function must be released in the close function.
Another example is if the plug-in needs to communicate with an external database. The connection is usually opened in the start function, and the connection must be closed in the close function.
In the plug-in init function, use the following parameters with slapi_pblock_set() to specify these functions:
SLAPI_PLUGIN_START_FN Specifies the function called after the Directory Server starts.
SLAPI_PLUGIN_CLOSE_FN Specifies the function called before the Directory Server shuts down.

7.2. Processing an LDAP Bind Operation

When the Directory Server receives an LDAP bind request from a client, the frontend determines the DN the client is attempting to bind and the authentication method being used. The frontend also gets the credentials used for authentication and, if SASL is used for authentication, the SASL mechanism used.

7.2.1. Defining Functions for the Bind Operation

In the parameter block, the following parameters specify plug-in functions that are called in the process of executing a bind operation:
  • The SLAPI_PLUGIN_PRE_BIND_FN parameter specifies the pre-operation bind function.
  • The SLAPI_PLUGIN_POST_BIND_FN parameter specifies the post-operation bind function.
To register the plug-in functions, call slapi_pblock_set() to set these parameters in your initialization function. Refer to Section 2.2.3, “Registering Your Plug-in Functions”.
Your pre-operation and post-operation bind functions should return 0 if successful. If the pre-operation function returns a non-zero value, the post-operation bind function is never called.
For information on defining a function that handles authentication, refer to Chapter 8, Defining Functions for Authentication.

7.2.2. Getting and Setting Parameters for the Bind Operation

The frontend makes this information available to pre-operation and post-operation plug-in functions in the form of parameters in a parameter block.

Table 7.1. Parameters for the Bind Operation

Parameter ID Data Type Description
SLAPI_BIND_TARGET char * DN of the entry as which to bind.
SLAPI_BIND_METHOD int Authentication method used; for example, LDAP_AUTH_SIMPLE or LDAP_AUTH_SASL.
SLAPI_BIND_CREDENTIALS struct berval * Credentials from the bind request.
SLAPI_BIND_RET_SASLCREDS struct berval * The credentials that you want sent to the client. Set this before calling slapi_send_ldap_result().
SLAPI_BIND_SASLMECHANISM char * SASL mechanism used; for example, LDAP_SASL_EXTERNAL.
If the SLAPI_BIND_SASLMECHANISM parameter is empty, simple authentication was used, and simple credentials were provided.

7.3. Processing an LDAP Unbind Operation

When the Directory Server receives an LDAP unbind request from a client, the frontend calls the nunbind function for each backend. No operation-specific parameters are placed in the parameter block that is passed to the unbind function.
In the parameter block, the following parameters specify plug-in functions that are called in the process of executing an unbind operation:
  • The SLAPI_PLUGIN_PRE_UNBIND_FN parameter specifies the pre-operation unbind function.
  • The SLAPI_PLUGIN_POST_UNBIND_FN parameter specifies the post-operation unbind function.
Call the slapi_pblock_set() function to set these parameters to the names of your functions.
Your plug-in functions should return 0 if successful. If the pre-operation function returns a non-zero value, the post-operation unbind function is never called.

7.4. Processing an LDAP Search Operation

The server processes an LDAP search operation in two stages:
  1. First, the server gets a list of candidate entries, using an index (if applicable).
    For example, for a search filter that finds entries where mail=a*, the server checks the index for the mail attribute (if the index exists), finds the keys that start with a, and generates a list of matching entries.
    If no applicable index exists, all entries are considered to be candidates.
    To get the list of candidates, the server calls the backend search function. For details, refer to Section 7.4.1, “Getting the List of Candidates”.
  2. Next, the server iterates through each candidate in the list and determines if the candidate matches the search criteria.
    If an entry matches the criteria, the server sends the entry to the client.
    To check each candidate, the server calls the backend next_candidate function for each candidate in the list. For details, refer to Section 7.4.2, “Iterating through Candidates”.
The rest of this section explains these stages in more detail.

7.4.1. Getting the List of Candidates

When the Directory Server receives an LDAP search request, the frontend gets information about the search (such as the scope and base DN). The frontend normalizes the base DN by calling the slapi_sdn_get_ndn() function and determines if the base DN identifies a DSA-specific entry (DSE). If so, the frontend handles the search request directly and does not pass it to the backend search function.
If the base DN is not a DSE, the frontend finds the backend that services the suffix specified in the base DN. The frontend then passes the search criteria to the search function for that backend.
The frontend makes this information available to pre-operation and post-operation plug-in functions in the form of parameters in a parameter block.

Table 7.2. Table of Information Available during an LDAP Search Operation

Parameter ID Data Type Description
SLAPI_SEARCH_TARGET char * DN of the base entry in the search operation (the starting point of the search).
SLAPI_ORIGINAL_TARGET_DN char * The original DN sent by the client (this DN is normalized by SLAPI_SEARCH_TARGET); read-only parameter.
SLAPI_SEARCH_SCOPE int The scope of the search. The scope can be one of the following values:
  • LDAP_SCOPE_BASE
  • LDAP_SCOPE_ONELEVEL
  • LDAP_SCOPE_SUBTREE
SLAPI_SEARCH_DEREF int Method for handling aliases in a search. This method can be one of the following values:
  • LDAP_DEREF_NEVER
  • LDAP_DEREF_SEARCHING
  • LDAP_DEREF_FINDING
  • LDAP_DEREF_ALWAYS
SLAPI_SEARCH_SIZELIMIT int Maximum number of entries to return in the search results.
SLAPI_SEARCH_TIMELIMIT int Maximum amount of time (in seconds) allowed for the search operation.
SLAPI_SEARCH_FILTER Slapi_Filter * Slapi_Filter struct (an opaque data structure) representing the filter to be used in the search.
SLAPI_SEARCH_STRFILTER char * String representation of the filter to be used in the search.
SLAPI_SEARCH_ATTRS char ** Array of attribute types to be returned in the search results.
SLAPI_SEARCH_ATTRSONLY int Specifies whether the search results return attribute types only or attribute types and values. (0 means return both attributes and values; 1 means return attribute types only).
Your search function should return 0 if successful. Call the slapi_pblock_set() function to assign the set of search results to the SLAPI_SEARCH_RESULT_SET parameter in the parameter block.
The frontend then uses this function in conjunction with the next entry function (refer to Section 7.4.2, “Iterating through Candidates”) to iterate through the result set. The frontend sends each result back to the client and continues updates the SLAPI_NENTRIES parameter with the current number of entries sent back to the client.
If a result is actually a referral, the frontend sends the referral back to the client and updates the SLAPI_SEARCH_REFERRALS parameter with the list of referral URLs.
Finally, after sending the last entry to the client, the frontend sends an LDAP result message specifying the number of entries found.

7.4.2. Iterating through Candidates

In addition to the parameters specified in Section 7.4, “Processing an LDAP Search Operation”, the next entry function has access to the following parameters (which are set by the frontend and the backend during the course of executing a search operation):

Table 7.3. Table of Information Available to the next entry Function

Parameter ID Data Type Description
SLAPI_SEARCH_RESULT_SET void * Set of search results. These data are specific to the backend processing the search. Any plug-in functions should not touch this value.
SLAPI_SEARCH_RESULT_ENTRY Slapi_Entry * Entry returned from iterating through the results set. This next entry function actually sets this parameter.
SLAPI_SEARCH_RESULT_ENTRY_EXT void * Reserved for future use. The context identifying the last result sent in the results set. This next entry function actually sets this parameter.
SLAPI_NENTRIES int Number of search results found.
SLAPI_SEARCH_REFERRALS struct berval ** NULL-terminated array of the URLs to other LDAP servers to which the current server is referring the client.
The next entry function should get the next result specified in the set of results in the SLAPI_SEARCH_RESULT_SET parameter. The function should set this next entry as the value of the SLAPI_SEARCH_RESULT_ENTRY parameter in the parameter block, and the next entry function should return 0 if successful.
The next entry function should set the SLAPI_SEARCH_RESULT_ENTRY parameter to NULL and return -1 if one of the following situations occurs:
  • The operation is abandoned (you can check this by calling the slapi_op_abandoned() function).
  • The time limit has been exceeded.
  • The maximum number of entries has been exceeded.
If no more entries exist in the set of results, the next entry function should set the SLAPI_SEARCH_RESULT_ENTRY parameter to NULL and return 0.

7.5. Processing an LDAP Compare Operation

When the Directory Server receives an LDAP compare request from a client, the frontend gets the DN of the entry being compared and the attribute and value being used in the comparison.
The frontend makes this information available to pre-operation and post-operation plug-in functions in the form of parameters in a parameter block.

Table 7.4. Table of Information Returned during an LDAP Compare Operation

Parameter ID Data Type Description
SLAPI_COMPARE_TARGET char * DN of the entry to be compared.
SLAPI_COMPARE_TYPE char * Attribute type to use in the comparison.
SLAPI_COMPARE_VALUE struct berval * Attribute value to use in the comparison.
The compare function should call slapi_send_ldap_result() to send LDAP_COMPARE_TRUE if the specified value is equal to the value of the entry's attribute or LDAP_COMPARE_FALSE if the values are not equal.
If successful, the compare function should return 0. If an error occurs (for example, if the specified attribute doesn't exist), the compare function should call slapi_send_ldap_result() to send an LDAP error code and should return 1.

7.6. Processing an LDAP Add Operation

When the Directory Server receives an LDAP add request from a client, the frontend normalizes the DN of the new entry. The frontend makes this information available to pre-operation and post-operation plug-in functions in the form of parameters in a parameter block.

Table 7.5. Table of Information Processed during an LDAP Add Operation

Parameter ID Data Type Description
SLAPI_ADD_TARGET char * DN of the entry to be added.
SLAPI_ADD_ENTRY Slapi_Entry * The entry to be added (specified as the opaque Slapi_Entry data type).
The add function should check if the operation has been abandoned, and, if it has, the function should return -1.

Note

It is not necessary to call slapi_send_ldap_result() to send an LDAP error code to the client. According to the LDAP protocol, the client does not expect a server response after an operation is abandoned.
These optional checks are not required. The plug-in can pass the operation to the regular frontend and backend processing which handle these cases.
  • If the entry already exists in the database, the function should call slapi_send_ldap_result() to send an LDAP error code LDAP_ALREADY_EXISTS and should return -1.
  • If the parent entry, or the closest matching entry, is a referral entry (that is, an entry with the object class ref) and no manageDSAIT control is included with the request, the function should call slapi_send_ldap_referral() to send a referral and return -1.
    To determine if a manageDSAIT control is present, call slapi_pblock_get() to get the value of the SLAPI_MANAGEDSAIT parameter. If the value is 1, the control is included in the request. If the value is 0, the control is not included in the request.
  • If the parent entry does not exist, the function should call slapi_send_ldap_result() to send an LDAP error code LDAP_NO_SUCH_OBJECT and return -1.
  • If the entry is not schema-compliant (call slapi_entry_schema_check() to determine this), the function should call slapi_send_ldap_result() to send the LDAP error code LDAP_OBJECT_CLASS_VIOLATION and should return -1.
  • If the requestor does not have permission to add the entry (call slapi_access_allowed() to determine this), the function should call slapi_send_ldap_result() to send the LDAP error code LDAP_INSUFFICIENT_ACCESS and should return -1.
You should also verify that the ACI syntax for the entry is correct; call slapi_acl_check_mods() to determine this.
If the add function is successful, the function should call slapi_send_ldap_result() to send an LDAP_SUCCESS code back to the client and should return 0.

7.7. Processing an LDAP Modify Operation

When the Directory Server receives an LDAP modify request from a client, the frontend gets the DN of the entry to be modified and the modifications to be made. The frontend makes this information available to pre-operation and post-operation plug-in functions in the form of parameters in a parameter block.

Table 7.6. Table of Information Processed during an LDAP Modify Operation

Parameter ID Data Type Description
SLAPI_MODIFY_TARGET char * DN of the entry to be modified.
SLAPI_MODIFY_MODS LDAPMod ** A NULL-terminated array of LDAPMod structures, which represent the modifications to be performed on the entry.
The modify function should check the following:
  • If the operation has been abandoned, the function should return -1.

    Note

    You do not need to call slapi_send_ldap_result() to send an LDAP error code to the client. According to the LDAP protocol, the client does not expect a server response after an operation is abandoned.
  • If the entry is a referral entry (that is, an entry with the object class ref) and no manageDSAIT control is included with the request, the function should call slapi_send_ldap_referral() to send a referral and return -1.
    To determine if a manageDSAIT control is present, call slapi_pblock_get() to get the value of the SLAPI_MANAGEDSAIT parameter. If the value is 1, the control is included in the request. If the value is 0, the control is not included in the request.
  • If the entry does not exist, check the following:
    • If the closest matching entry is a referral entry, and if no manageDSAIT control is included in the request, the function should call slapi_send_ldap_referral() to send a referral and return -1.
    • Otherwise, the function should call slapi_send_ldap_result() to send an LDAP error code LDAP_NO_SUCH_OBJECT and return -1.
  • If the entry is not schema-compliant (call slapi_entry_schema_check() to determine this), the function should call slapi_send_ldap_result() to send the LDAP error code LDAP_OBJECT_CLASS_VIOLATION and should return -1.
  • If the RDN of the entry contains attribute values that are not part of the entry (for example, if the RDN is uid=bjensen, but the entry has no uid value or has a different uid value), the function should call slapi_send_ldap_result() to send the LDAP error code LDAP_NOT_ALLOWED_ON_RDN and should return -1.
  • If the requester does not have permission to modify the entry (call slapi_access_allowed() to determine this), the function should call slapi_send_ldap_result() to send the LDAP error code LDAP_INSUFFICIENT_ACCESS and should return -1.
You should also verify that the ACI syntax for the entry is correct; call slapi_acl_check_mods() to determine this.
If the modify function is successful, the function should call slapi_send_ldap_result() to send an LDAP_SUCCESS code back to the client and should return 0.

7.8. Processing an LDAP Modify RDN Operation

When the Directory Server receives an LDAP modifyRDN request from a client, the frontend gets the original DN of the entry, the new RDN, and, if the entry is moving to a different location in the directory tree, the DN of the new parent of the entry.
The frontend makes this information available to pre-operation and post-operation plug-in functions in the form of parameters in a parameter block.

Table 7.7. Table of Information Processed during an LDAP ModifyRDN Operation

Parameter ID Data Type Description
SLAPI_MODRDN_TARGET char * DN of the entry that you want to rename.
SLAPI_MODRDN_NEWRDN char * New RDN to assign to the entry.
SLAPI_MODRDN_DELOLDRDN int Specifies whether to delete the old RDN.
  • 0 - Do not delete the old RDN.
  • 1 - Delete the old RDN
SLAPI_MODRDN_NEWSUPERIOR char * DN of the new parent of the entry, if the entry is being moved to a new location in the directory tree.
The modify RDN function should check the following:
  • If the operation has been abandoned, the function should return -1.

    Note

    You do not need to call slapi_send_ldap_result() to send an LDAP error code to the client. According to the LDAP protocol, the client does not expect a server response after an operation is abandoned.
  • If the entry is a referral entry (that is, an entry with the object class ref) and no manageDSAIT control is included with the request, the function should call slapi_send_ldap_referral() to send a referral and return -1.
    To determine if a manageDSAIT control is present, call slapi_pblock_get() to get the value of the SLAPI_MANAGEDSAIT parameter. If the value is 1, the control is included in the request. If the value is 0, the control is not included in the request.
  • If the entry does not exist, check the following:
    • If the closest matching entry is a referral entry, and if no manageDSAIT control is included in the request, the function should call slapi_send_ldap_referral() to send a referral and return -1.
    • Otherwise, the function should call slapi_send_ldap_result() to send an LDAP error code LDAP_NO_SUCH_OBJECT and return -1.
  • If the entry is not schema-compliant (call slapi_entry_schema_check() to determine this), the function should call slapi_send_ldap_result() to send the LDAP error code LDAP_OBJECT_CLASS_VIOLATION and should return -1.
  • If the RDN of the entry contains attribute values that are not part of the entry (for example, if the RDN is uid=bjensen, but the entry has no uid value or has a different uid value), the function should call slapi_send_ldap_result() to send the LDAP error code LDAP_NOT_ALLOWED_ON_RDN and should return -1.
  • If the requester does not have permission to modify the entry (call slapi_access_allowed() to determine this), the function should call slapi_send_ldap_result() to send the LDAP error code LDAP_INSUFFICIENT_ACCESS and should return -1.
You should also verify that the ACI syntax for the entry is correct; call slapi_acl_check_mods() to determine this.
If the modifyRDN function is successful, the function should call slapi_send_ldap_result() to send an LDAP_SUCCESS code back to the client and should return 0.

7.9. Processing an LDAP Delete Operation

When the Directory Server receives an LDAP delete request from a client, the frontend gets the DN of the entry to be removed from the directory. The frontend makes this information available to pre-operation and post-operation plug-in functions in the form of parameters in a parameter block.

Table 7.8. Table of Information Processed during an LDAP Delete Operation

Parameter ID Data Type Description
SLAPI_DELETE_TARGET char * DN of the entry to delete.
If the delete function is successful, it should return 0.

7.10. Processing an LDAP Abandon Operation

When the Directory Server receives an LDAP abandon request from a client, the frontend gets the message ID of the operation that should be abandoned. The frontend makes this information available to pre-operation and post-operation plug-in functions in the form of parameters in a parameter block.

Table 7.9. Table of Information Processed during an LDAP Abandon Operation

Parameter ID Data Type Description
SLAPI_ABANDON_MSGID unsigned long Message ID of the operation to abandon.

Chapter 8. Defining Functions for Authentication

This chapter explains how to write a plug-in function to bypass or replace the standard function for authentication with your own function.

8.1. Understanding Authentication Methods

Authentication methods for LDAP is described in RFC 4513, available at http://www.ietf.org/rfc/rfc4513.txt.
Two methods that you can use to authenticate clients are simple authentication and SASL authentication:
  • Simple authentication is described in RFC 4513, available at http://www.ietf.org/rfc/rfc4513.txt.
    Simple authentication provides minimal facilities for authentication. In the simple authentication method, clients send a DN and password to the server for authentication. The server compares the password sent by the client against the password stored in the client's directory entry.
  • Simple Authentication and Security Layer (SASL) is described in RFC 4422, which you can find at http://www.ietf.org/rfc/rfc4422.txt.
    SASL provides the means to use mechanisms other than simple authentication and SSL to authenticate to the Directory Server.

8.2. How the Directory Server Identifies Clients

The server keeps track of the identity of the LDAP client through the SLAPI_CONN_DN and SLAPI_CONN_AUTHTYPE parameters.
During an LDAP bind operation, the server authenticates the user and puts the DN and authenticated method in the SLAPI_CONN_DN and SLAPI_CONN_AUTHTYPE parameters.
When an authenticated client requests the server to perform an LDAP operation, the server checks the DN in the SLAPI_CONN_DN parameter to determine if the client has the appropriate access rights.

8.3. How the Authentication Process Works

When the Directory Server receives an LDAP bind request from a client, it processes the request as follows:

Procedure 8.1. How an Authentication Request is Processed

  1. The server parses the LDAP bind request and retrieves the following information:
    • The DN as which the client is attempting to authenticate.
    • The method of authentication used.
    • Any credentials (such as a password) included in the request.
    If the method of authentication is LDAP_AUTH_SASL (SASL authentication), the server also retrieves the name of the SASL mechanism used from the LDAP bind request.
  2. The server normalizes the DN retrieved from the request. (Refer to the slapi_sdn_get_ndn() function for more information on normalized DNs.)
  3. The server retrieves any LDAPv3 controls included with the LDAP bind request.
  4. If the method of authentication is LDAP_AUTH_SASL (SASL authentication), the server determines whether the SASL mechanism (specified in the request) is supported.
    If the SASL mechanism is not supported by the server, the server sends an LDAP_AUTH_METHOD_NOT_SUPPORTED result code back to the client and ends the processing of the bind request.
  5. If the method of authentication is LDAP_AUTH_SIMPLE (simple authentication), the server checks if the DN is an empty string or if there are no credentials.
    If the DN is an empty string, if the DN is not specified, or if no credentials are specified, the server assumes that the client is binding anonymously and sends an LDAP_SUCCESS result code back to the client.
    The DN and authentication method for the connection, which are used to determine access rights for all operations performed through the connection, are left as NULL and SLAPD_AUTH_NONE, respectively.
  6. If the DN specified in the request is not served by this Directory Server (for example, if the DN is uid=moxcross,dc=example,dc=com, and the directory root of the server is dc=example,dc=com), the server sends one of the following two results back to the client and ends the processing of the bind request:
    • If the server is configured with a default referral (that is, an LDAP URL which identifies an LDAP server that handles referrals), the server sends an LDAP_REFERRAL result code back to the client, or LDAP_PARTIAL_RESULTS if the client only supports the LDAPv2 protocol.
    • If the server is not configured with a default referral, the server sends an LDAP_NO_SUCH_OBJECT result code back to the client.
  7. The server puts the information from the bind request into the parameter block:
    • SLAPI_BIND_TARGET is set to the DN as which the client is authenticating.
    • SLAPI_BIND_METHOD is set to the authentication method (for example, LDAP_AUTH_SIMPLE or LDAP_AUTH_SASL).
    • SLAPI_BIND_CREDENTIALS is set to the credentials (for example, the password) included in the request.
    • SLAPI_BIND_SASLMECHANISM (if the authentication method is LDAP_AUTH_SASL) is set to the name of the SASL mechanism that the client is using for authentication.
  8. If the DN is the root DN or the update DN (the DN of the master entity responsible for replicating the directory), the server authenticates the client.
    • If the credentials are correct, the server sets the SLAPI_CONN_DN parameter to the DN and the SLAPI_CONN_AUTHTYPE parameter to LDAP_AUTH_SIMPLE. The server sends an LDAP_SUCCESS result code back to the client and ends the processing of the bind request.
    • If the credentials are incorrect, the server sends an LDAP_INVALID_CREDENTIALS result code back to the client and ends the processing of the bind request.
  9. At this point, the server calls any pre-operation bind plug-in functions. If the function returns a non-zero value, the server ends the processing of the bind request.
    If you are writing your own plug-in function to handle authentication, you should return a non-zero value so that the server does not attempt to continue processing the bind request.
  10. The server calls the backend bind function. The bind function returns one of the following values:
    • If the function returns a non-zero value, the server ends the processing of the bind request. The bind function is responsible for sending the appropriate result code back to the client before returning a non-zero value.
    • If the function returns 0, the server continues processing the bind request. The server sends the LDAP_SUCCESS result code back to the client. (The bind function does not do this.)
  11. If the backend bind function succeeds, the server sets the SLAPI_CONN_DN parameter to the DN, and the SLAPI_CONN_AUTHTYPE parameter to the authentication method.
  12. The server sends an LDAP_SUCCESS result code back to the client and ends the processing of the bind request.
    If the client's password is due to expire, the server includes a password expiring control (with the OID 2.16.840.1.113730.3.4.5) as part of the result sent to the client. If the client is logging in for the first time and needs to change the password, the server includes a password expired control (with the OID 2.16.840.1.113730.3.4.4) as part of the result sent to the client.

8.4. Writing Your Own Authentication Plug-in

The situation may arise where you want to write and implement your own authentication function; that is, replace the standard means of authentication with your own function. You can write a pre-operation bind plug-in function (a function that the server calls before processing an LDAP bind request) that performs the authentication and bypasses the default bind functionality. This is described in the following section.

8.5. Writing a Pre-Operation Bind Plug-in

You can define your own pre-operation bind plug-in function to authenticate LDAP clients. The server will call your function during the authentication process. See Procedure 8.1, “How an Authentication Request is Processed” for more information on the authentication process. Your function should return a non-zero value to bypass the default backend bind function and the post-operation bind functions.
This means that the final steps of the authentication process are skipped. Your pre-operation plug-in function is responsible for sending the result code to the client and for setting the DN and authentication method for the connection.
Figure 8.1, “Using a Pre-Operation bind Plug-in Function to Handle Authentication” summarizes the process of using a pre-operation bind plug-in function to authenticate LDAP clients to the Directory Server.
Using a Pre-Operation bind Plug-in Function to Handle Authentication

Figure 8.1. Using a Pre-Operation bind Plug-in Function to Handle Authentication

Figure 8.2, “How Your Pre-Operation Bind Plug-in Function Can Authenticate LDAP Clients” illustrates the steps that your pre-operation bind plug-in function must take to authenticate LDAP clients to the Directory Server.
How Your Pre-Operation Bind Plug-in Function Can Authenticate LDAP Clients

Figure 8.2. How Your Pre-Operation Bind Plug-in Function Can Authenticate LDAP Clients

8.5.1. Defining the Authentication Function

Note

Check out the sample testbind.c source file as an example of a pre-operation plug-in function that handles authentication. This file is in the install_directory//ldapserver/ldap/servers/slapd/test-plugins/ directory.
Sample plug-in files are installed separately from other Directory Server packages, available at the 389 Directory Server repos, http://git.fedorahosted.org/cgit/389/ds.git/tree/ldap/servers/plugins and http://git.fedorahosted.org/cgit/389/ds.git/tree/ldap/servers/slapd/test-plugins. These sample plug-in files can be installed in any directory.

8.5.1.1. Getting and Checking the Bind Parameters

Call the slapi_pblock_get() function to get the values of the following parameters:
  • SLAPI_BIND_TARGET - A string value specifying the DN as which the client is attempting to authenticate.
  • SLAPI_BIND_METHOD - An integer value specifying the authentication method, such as LDAP_AUTH_SIMPLE or LDAP_AUTH_SASL.
  • SLAPI_BIND_CREDENTIALS - A berval structure containing the credentials sent by the client.
If you plan to support authentication through SASL mechanisms, you should also get the value of the SLAPI_BIND_SASLMECHANISM parameter (a string value specifying the name of the SASL mechanism to use for authentication).
To handle the bind operation entirely within the plug-in, with no further frontend or backend processing, do the following:
  • Determine if the client is requesting to bind as an anonymous user.
    If the SLAPI_BIND_METHOD parameter is LDAP_AUTH_SIMPLE and the SLAPI_BIND_CREDENTIALS parameter is empty or NULL, the client is attempting to bind anonymously. Alternatively, disallow an anonymous bind and return the LDAP result code LDAP_UNWILLING_TO_PERFORM.
    Call slapi_send_ldap_result() to send the LDAP result code LDAP_SUCCESS back to the client.
  • If the SLAPI_BIND_METHOD parameter specifies a method that you do not recognize or support, call slapi_send_ldap_result() to send an LDAP_STRONG_AUTH_NOT_SUPPORTED result code back to the client.
In both cases, return a non-zero value as the plug-in function return value to prevent the server from calling the default backend function for authentication.

8.5.1.2. Getting the Entry and Checking the Credentials

Get the entry for the DN specified by the SLAPI_BIND_TARGET parameter, and compare the credentials in the SLAPI_BIND_CREDENTIALS parameter against the known credentials for that entry. In order to get the entry, you must perform an internal search. There are several functions that can be used, listed in order of increasing power and complexity:
Then, it is possible to use the attribute and value functions listed in Table 5.1, “Frontend Functions for Manipulating Entries and Attributes” to get the values.
Directory Server uses the userPassword attribute to store the credentials for an entry. The server encodes the password using the scheme specified in the nsslapd-rootpwstoragescheme attribute for the Directory Manager or passwordStorageScheme attribute for other users. These attributes are defined in the cn=config entry contained in the dse.ldif file. The scheme can be any of the following:
  • CLEAR — No encryption is used, and can be defined using the clear-password-storage-scheme plug-in.
  • CRYPT — Uses the Unix crypt algorithm, and can be defined using the crypt-password-storage-scheme plug-in.
  • SHA, SHA256, SHA384, SHA512 — Uses the Secure Hashing Algorithm, and can be defined using the sha-password-storage-scheme plug-in. SHA is SHA-1, which is 140 bits. For the others, the number indicates the number of bits used by the hash.
  • SSHA, SSHA256, SSHA384, SSHA512 — Uses the Salted Secure Hashing Algorithm, and can be defined using the ssha-password-storage-scheme plug-in. SSHA is SSHA-1, which is 140 bits, including the salt. For the others, the number indicates the number of bits used by the hash, including the salt.
To compare the client's credentials against the value of the userPassword attribute, you can call the slapi_pw_find_sv() function. This function determines which password scheme was used to store the password and uses the appropriate comparison function to compare a given value against the encrypted value of the userPassword attribute.

8.5.1.3. What to Do If Authentication Fails

If authentication fails, send one of the following result codes back to the client:
  • If no entry matches the DN specified by the client, send an LDAP_NO_SUCH_OBJECT result code back to the client.
    When calling the slapi_send_ldap_result() function to send the result code back to the client, specify the closest matching DN as the matched argument.
  • If the client fails to provide the necessary credentials, or if credentials cannot be found in the entry, send an LDAP_INAPPROPRIATE_AUTH result code back to the client.
  • If the credentials specified by the client do not match the credentials found in the entry, send an LDAP_INVALID_CREDENTIALS result code back to the client.
  • If a general error occurs, send an LDAP_OPERATIONS_ERROR result code back to the client.
Your function should also return a non-zero value.
You do not need to set any values for the SLAPI_CONN_DN parameter and the SLAPI_CONN_AUTHTYPE parameter. By default, these parameters are set to NULL and LDAP_AUTH_NONE, which indicate that the client has bound anonymously.

8.5.1.4. What to Do If Authentication Succeeds

If the authentication is successful, your authentication function should:
  • Call slapi_pblock_set() to set the values of the SLAPI_CONN_DN parameter and the SLAPI_CONN_AUTHTYPE parameter to the DN and authentication method.
    This sets the DN and authentication method for the connection to the client. The server uses this DN and method in subsequent operations when checking access rights.
    You can set SLAPI_CONN_AUTHTYPE to one of the following values:
    • SLAPD_AUTH_NONE represents no authentication. (The client is binding anonymously.)
    • SLAPD_AUTH_SIMPLE represents the simple authentication method.
    • SLAPD_AUTH_SSL represents authentication through SSL.
    • SLAPD_AUTH_SASL represents SASL authentication.
    These values differ from the values in the SLAPI_BIND_METHOD parameter. The values listed above are string values defined in the slapi-plugin.h header file, whereas the values of the SLAPI_BIND_METHOD parameter (such as LDAP_AUTH_SIMPLE and LDAP_AUTH_SASL) are integer values defined in the ldap.h header file.
  • If required, specify the credentials that you want sent back to the client.
    If the value of the SLAPI_BIND_METHOD parameter is LDAP_AUTH_SASL and you want to return a set of credentials to the client, call slapi_pblock_set() to set the SLAPI_BIND_RET_SASLCREDS parameter to the credentials.
  • Send the result of the authentication process back to the client.
    Call slapi_send_ldap_result() to send an LDAP_SUCCESS return code to the client.
Make sure that your function returns a non-zero value to bypass the default backend bind function and any post-operation plug-in functions.

8.5.2. Registering the SASL Mechanism

If you are using SASL as the authentication method, you need to register the SASL mechanisms that you plan to use.
In your initialization function (see Section 2.2, “Writing Plug-in Initialization Functions”), call the slapi_register_supported_saslmechanism() function and specify the name of the SASL mechanism. For example:
slapi_register_supported_saslmechanism( "babsmechanism" );
If you do not register your SASL mechanism, the Directory Server will send an LDAP_AUTH_METHOD_NOT_SUPPORTED result code back to the client and will not call your pre-operation bind function.

Note

Check out the sample testsaslbind.c source file as an example of a pre-operation plug-in function for SASL authentication. This file is in the install_directory//ldapserver/ldap/servers/slapd/test-plugins/ directory.
Sample plug-in files are installed separately from other Directory Server packages, available at the 389 Directory Server repos, http://git.fedorahosted.org/cgit/389/ds.git/tree/ldap/servers/plugins and http://git.fedorahosted.org/cgit/389/ds.git/tree/ldap/servers/slapd/test-plugins. These sample plug-in files can be installed in any directory.

8.5.3. Example of a Pre-Operation Bind Plug-in

The following sections document an example of a pre-operation bind plug-in that handles authentication.

Note

Check out the sample testbind.c source file as an example of a pre-operation plug-in function that handles authentication. This file is in the install_directory//ldapserver/ldap/servers/slapd/test-plugins/ directory.
Sample plug-in files are installed separately from other Directory Server packages, available at the 389 Directory Server repos, http://git.fedorahosted.org/cgit/389/ds.git/tree/ldap/servers/plugins and http://git.fedorahosted.org/cgit/389/ds.git/tree/ldap/servers/slapd/test-plugins. These sample plug-in files can be installed in any directory.

8.5.3.1. Example of a Pre-Operation Bind Function

The following is an example of a pre-operation bind function that authenticates clients and bypasses the default backend bind function. In this example, the function compares the client's credentials against the value of the userpassword attribute for the entry.
#include <stdio.h>
#include <string.h>
#include "dirsrv/slapi-plugin.h"
/* Pre-operation plug-in function */

int test_bind(Slapi_PBlock *pb )
{
  Slapi_DN *dn;
  int method, rc = LDAP_SUCCESS;
  struct berval *credentials;
  Slapi_Entry *e = NULL;
  Slapi_Attr *attr = NULL;
  Slapi_ValueSet *vs = NULL;
  Slapi_Value *sv_creds = NULL;
  Slapi_DN *sdn = NULL;
  /* we only care about these attributes */
  char *attrlist[] = { "userPassword", NULL };
  
  /* Log a message to the server error log. */
  slapi_log_error( SLAPI_LOG_PLUGIN, "test_bind", "Pre-operation bind function called.\n" );
  /* Gets parameters available when processing an LDAP bind operation. */
  
  if ( slapi_pblock_get( pb, SLAPI_BIND_TARGET, &dn ) != 0 ||
       slapi_pblock_get( pb, SLAPI_BIND_METHOD, &method ) != 0 ||
       slapi_pblock_get( pb, SLAPI_BIND_CREDENTIALS, &credentials ) != 0 ) {
    slapi_log_error( SLAPI_LOG_PLUGIN, "test_bind" ,"Could not get parameters for bind operation\n" );
    slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR,
    NULL, NULL, 0, NULL );
    return( 1 );
  }
  sv_creds = slapi_value_new_berval(credentials); /* wrap in Slapi_Value* */
  sdn = slapi_sdn_new_dn_byref(dn); /* wrap in Slapi_DN* */
  /* Check the authentication method */
  switch( method ) {
  case LDAP_AUTH_SIMPLE:
    /* First, get the entry specified by the DN. */
	rc = slapi_search_internal_get_entry(sdn, attrlist, &e, my_plugin_identity);
    if ((LDAP_SUCCESS == rc) && (NULL != e)) {
      Slapi_Value **sva;
      /* see if the entry has the userpassword attribute */
      if ( slapi_entry_attr_find( e, "userpassword" , &attr ) != 0 ) {
        slapi_log_error( SLAPI_LOG_PLUGIN, "test_bind" ,"Entry has no
userpassword attribute\n" );
        rc = LDAP_INAPPROPRIATE_AUTH;
        break;
      }
      slapi_attr_get_valueset( attr, &vs ); /* must free vs */
      sva = valueset_get_valuearray( vs ); /* do not free sva */
      /* Next, check the credentials against the userpassword attribute
      of that entry. */
      if ( slapi_pw_find_sv( sva, sv_creds ) != 0 ) {
        slapi_log_error( SLAPI_LOG_PLUGIN, "test_bind" ,
          "Credentials are not correct for the entry\n" );
          rc = LDAP_INVALID_CREDENTIALS;
          break;
      }
      /* Set the DN and the authentication method for the connection. */
      if ( slapi_pblock_set( pb, SLAPI_CONN_DN, slapi_ch_strdup( dn ) ) != 0 ||
           slapi_pblock_set( pb, SLAPI_CONN_AUTHTYPE, SLAPD_AUTH_SIMPLE) != 0 ) {
        slapi_log_error( SLAPI_LOG_PLUGIN, "testbind_init" ,
        "Failed to set DN and auth method for connection\n" );
        rc = LDAP_OPERATIONS_ERROR;
        break;
      }
      /* Send a success result code back to the client. */
      slapi_log_error( SLAPI_LOG_PLUGIN, "test_bind" , "Authenticated: %s\n" , dn );
      rc = LDAP_SUCCESS;
    } else { /* error code or no entry */
        slapi_log_error( SLAPI_LOG_PLUGIN, "test_bind" ,"Could not find entry for %s: Error: %s\n" , dn, (rc == LDAP_SUCCESS) ? "unknown" : ldap_err2string(rc) );
        /* if the entry was null, there was probably an internal error */
        if (LDAP_SUCCESS == rc) {
            rc == LDAP_OPERATIONS_ERROR;
        }
    }
    break;
  /* If NONE is specified, the client is requesting to bind anonymously.
     Normally, this case should be handled by the server's front-end
     before it calls this plug-in function. Just in case this does
     get through to the plug-in function, you can handle this by
     sending a successful result code back to the client and returning 1,
     or if you do not want to support anon, return LDAP_UNWILLING_TO_PERFORM  */
  case LDAP_AUTH_NONE:
    slapi_log_error( SLAPI_LOG_PLUGIN, "test_bind" , "Authenticating anonymously\n" );
    rc = LDAP_SUCCESS; /* or return LDAP_UNWILLING_TO_PERFORM if anon not supported */
    break;
    /* This plug-in does not support any other method of authentication */
  case LDAP_AUTH_SASL:
  default:
    slapi_log_error( SLAPI_LOG_PLUGIN, "test_bind" ,
      "Unsupported authentication method requested: %d\n" , method );
    rc = LDAP_AUTH_METHOD_NOT_SUPPORTED;
    break;
  }

  /* clean up - ok to pass NULL to these */
  slapi_entry_free(e);
  slapi_valueset_free(vs);
  slapi_value_free(&creds_sv);
  slapi_sdn_free(&sdn);

  /* actually return the result to the client */
  slapi_send_ldap_result( pb, rc, NULL, NULL, 0, NULL );
  /* 1 here means we already handled it - server should not do any more processing */
  return( 1 );
}

8.5.3.2.  Example of an Initialization Function

To initialize your plug-in, write an initialization function to:
The following is an example of an initialization function that registers the pre-operation bind function.
#include <stdio.h>
#include <string.h>
#include "dirsrv/slapi-plugin.h"

Slapi_PluginDesc bindpdesc = { "test-bind" , "Red Hat" , "0.5" ,"sample bind pre-operation plugin" };

/* our plug-in identity . set in init function */
static Slapi_ComponentId *my_plugin_identity;

/* Initialization function */
#ifdef _WIN32
__declspec(dllexport)
#endif

int
testbind_init( Slapi_PBlock *pb )
{
  /* get our plug-in identity . we will need this to perform
     any internal operations (search, modify, etc.) */
  slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &my_plugin_identity);
  /* Register the pre-operation bind function and specify
  the server plug-in version. */
  if
  ( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION,SLAPI_PLUGIN_VERSION_03 ) != 0 ||
    slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION,(void *)&bindpdesc ) != 0 ||
    slapi_pblock_set( pb, SLAPI_PLUGIN_PRE_BIND_FN,(void *) test_bind ) != 0 )
  {
    slapi_log_error( SLAPI_LOG_PLUGIN, "testbind_init" , "Failed to set version and function\n" );
    return( -1 );
  }
  return( 0 );
}

8.5.3.3. Registering the Plug-in

To register the plug-in, add the following to the end of the /etc/dirsrv/slapd-instance_name/dse.ldif file:
dn: cn=Test Bind,cn=plugins,cn=config
objectClass: top
objectClass: nsSlapdPlugin
objectClass: extensibleObject
cn: Test Bind
nsslapd-pluginPath:/path/to/test-plugin.so   
nsslapd-pluginInitfunc: testbind_init
nsslapd-pluginType: preoperation
nsslapd-pluginEnabled: on
nsslapd-plugin-depends-on-type: database
nsslapd-pluginId: test-bind
Check out the sample testbind.c source file as an example of a pre-operation plug-in function that handles authentication. This file is in the install_directory//ldapserver/ldap/servers/slapd/test-plugins/ directory.

Note

Sample plug-in files are installed separately from other Directory Server packages, available at the 389 Directory Server repos, http://git.fedorahosted.org/cgit/389/ds.git/tree/ldap/servers/plugins and http://git.fedorahosted.org/cgit/389/ds.git/tree/ldap/servers/slapd/test-plugins. These sample plug-in files can be installed in any directory.
There are also examples in the source code itself. Look in the install_directory/ldapserver/ldap/servers/plugins directory for plug-ins that implement SLAPI_PLUGIN_PRE_BIND_FN.
The example code given is very basic. There are many other things which a bind plug-in could do. For example:
  • Log the authentication attempt to the access log for auditing.
  • Check for password expiration and use slapi_add_pwd_control() to send that information back to the client.
  • See if the client has requested additional password policy information in a couple of different ways:
    slapi_pblock_get (pb, SLAPI_REQCONTROLS, ...) 
    slapi_pblock_get (pb, SLAPI_PWPOLICY, ...)
    Then send the requested information back to the client using slapi_pwpolicy_make_response_control().
  • Manage other aspects of password policy.
Finally, take a look at the server bind code in bind.c to see what sort of processing it does.

Chapter 9. Writing Entry Store/Fetch Plug-ins

This chapter describes how to write entry store and entry fetch plug-ins. You can use these types of plug-ins to invoke functions before and after data is read from the default database.

9.1. How Entry Store/Fetch Plug-ins Work

Entry store plug-in functions are called before data is written to the database. Entry fetch plug-in functions are called after data is read from the default database. This processing is illustrated in Figure 9.1, “How the Server Calls Entry Store and Entry Fetch Plug-in Functions”.
How the Server Calls Entry Store and Entry Fetch Plug-in Functions

Figure 9.1. How the Server Calls Entry Store and Entry Fetch Plug-in Functions

9.2. Writing Entry Store/Fetch Functions

Unlike most other types of plug-in functions, a parameter block is not passed to entry store and entry fetch plug-in functions when they are called. Instead, entry store and entry fetch plug-in functions must have the following prototype:
void function_name( char **entry, unsigned long *len );
The function parameters are described below:
  • entry — Pointer to a string specifying the entry in LDIF format; for details on this format, see slapi_str2entry() and slapi_entry2str().
  • len — Pointer to the length of the entry string.
Because the text of the entry is passed in as an argument, you can modify the entry before it gets saved to disk and modify the entry after it is read from disk. The pointer can be reallocated to get more room. For example:
  void my_entry_fetch( char **entry, unsigned long *len )
  {
    ...
    *len = newsize;
    *entry = slapi_ch_realloc(*entry, (*len) * sizeof(char));
    ... append to *entry ...
  }
The server calls slapi_ch_free() to free the memory, so to allocate more memory, use one of the slapi memory allocation functions.

Note

The testentry.c sample file has example entry store and entry fetch plug-in functions. This example file is with other examples in the install_directory/ldapserver/ldap/servers/plugins directory.

9.3. Registering Entry Store/Fetch Functions

The plug-in configuration entry is much like that for other types of plug-ins. The nsslapd-pluginType is ldbmentryfetchstore. The plug-in init function should register the entry fetch callback using slapi_pblock_set() with SLAPI_PLUGIN_ENTRY_FETCH_FUNC and register the entry store callback using slapi_pblock_set() with SLAPI_PLUGIN_ENTRY_STORE_FUNC. It is not necessary to have both functions; it is possible to use only a fetch or only a store function.
It is also possible to register a start and a close function.
To register an entry store or entry fetch plug-in function, edit the Directory Server's dse.ldif file configuration file and add the entry:
  1. Add the plug-in parameters to the dse.ldif file. For example:
    ldapmodify -D "cn=directory manager" -W -p 389 -h server.example.com -x
    
    dn: cn=Test entry,cn=plugins,cn=config
    objectClass: top
    objectClass: nsSlapdPlugin
    objectClass: extensibleObject
    cn: Test entry
    nsslapd-pluginPath: /path/to/test-plugin.so
    nsslapd-pluginInitfunc: testentry_init
    nsslapd-pluginType: ldbmentryfetchstore
    nsslapd-pluginEnabled: on
    nsslapd-pluginId: test-entry
  2. Restart the server to load the new plug-in.
    service dirsrv restart
The testentry.c source file has an example plug-in function that implements entry store and entry fetch operations. Example files are installed in install_directory/ldapserver/ldap/servers/plugins.

Chapter 10. Writing Extended Operation Plug-ins

This chapter explains how to write plug-in functions to handle extended operations. Extended operations are defined in the LDAP v3 protocol.

10.1. How Extended Operation Plug-ins Work

You can define your own operation that you want the Red Hat Directory Server to perform. If you create a custom extended operation, you assign an object identifier (OID) to identify that operation. LDAP clients request the operation by sending an extended operation request. Within the request, the client specifies:
  • The OID of the extended operation.
  • Data specific to the extended operation.
When the Directory Server receives the request, the server calls the plug-in registered with the specified OID. The plug-in function has access to both the OID and the data in the client's request. The plug-in function can send a response back to the client containing an OID plus any additional data that might be needed.
In order to use extended operations, you need to configure both the Directory Server and the client so that they understand the specific extended operation that you want to perform.

10.2. Writing Extended Operation Functions

Like other plug-in functions, extended operation functions pass a single parameter block (Slapi_PBlock) and return an integer value, as shown in the following example declaration:
int my_ext_func( Slapi_PBlock *pb );
When the Directory Server receives an extended operation request, the front-end calls the extended operation function with the OID value specified in the request. The front-end makes the following information available to the extended function in the form of parameters in a parameter block.

Table 10.1. Extended Function Parameter Block Arguments

Parameter ID Data Type Description
SLAPI_EXT_OP_REQ_OID char * Object ID (OID) of the extended operation specified in the request.
SLAPI_EXT_OP_REQ_VALUE struct berval* Value specified in the request.
SLAPI_EXT_OP_RET_OID char * Object ID (OID) that you want sent back to the client.
SLAPI_EXT_OP_RET_VALUE struct berval* Value that you want sent back to the client.
Typically, your function should perform an operation on the value specified in the SLAPI_EXT_OP_REQ_VALUE parameter. After the extended operation completes, your function should return a single value, according to the following:
  • If your function has sent a result code back to the client, you should return the value SLAPI_PLUGIN_EXTENDED_SENT_RESULT. This indicates that the front-end does not need to send a result code.
  • If your function has not sent a result code back to the client (for example, if the result is LDAP_SUCCESS), your function should return an LDAP result code. The front-end will send this result code back to the client.
  • If your function cannot handle the extended operation with the specified OID, your function should return the value SLAPI_PLUGIN_EXTENDED_NOT_HANDLED. The front-end will send an LDAP_PROTOCOL_ERROR result code (with an unsupported extended operation error message) back to the client.

Note

Check out the testextendedop.c source file for a sample plug-in function (uncompiled C code) that implements an extended operation.

10.3. Registering Extended Operation Functions

Extended operation functions are specified in a parameter block that you can set on server startup, in the same fashion as other server plug-in functions (refer to Section 2.1.2, “Passing Data with Parameter Blocks”).
In your initialization function, you can call the slapi_pblock_set() function to set the SLAPI_PLUGIN_EXT_OP_FN parameter to your function and the SLAPI_PLUGIN_EXT_OP_OIDLIST parameter to the list of OIDs of the extended operations supported by your function.
You can write your initialization function so that the OID is passed in from the directive (refer to Section 3.3, “Passing Extra Arguments to Plug-ins”, for details.) For example, the following initialization function sets the SLAPI_PLUGIN_EXT_OP_OIDLIST parameter to the additional parameters specified.
int extended_init( Slapi_PBlock *pb )
{
  int i;
  char **argv;
  char **oids;
  
  /* Get the additional arguments specified in the directive */
  if ( slapi_pblock_get( pb, SLAPI_PLUGIN_ARGV, &argv ) != 0 ) {
    slapi_log_error( SLAPI_LOG_PLUGIN, extended_init , Server could not get argv.\n );
    return( -1 );
  }
  if ( argv == NULL ) {
    slapi_log_error( SLAPI_LOG_PLUGIN, extended_init , Required argument oiD is missing\n );
    return( -1 );
  }
  
  /* Get the number of additional arguments and copy them. */
  for ( i = 0; argv[i] != NULL;i++ )
  ;
  oids = (char **) slapi_ch_malloc( (i+1) * sizeof(char *) );
  for ( i = 0; argv[i] != NULL; i++ ) {
    oids[i] = slapi_ch_strdup( argv[i] );
  }
  oids[i] = NULL;
  
  /* Specify the version of the plug-in */
  if ( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01 ) != 0 ||
  
  /* Specify the OID of the extended operation */
  slapi_pblock_set( pb, SLAPI_PLUGIN_EXT_OP_OIDLISTs, (void*) oids ) != 0 ||
  
  /* Specify the function that the server should call */
  slapi_pblock_set( pb, SLAPI_PLUGIN_EXT_OP_FN, (void*)extended_op ) != 0 ) {
    slapi_log_error( SLAPI_LOG_PLUGIN, extended_init , An error occurred.\n );
    return( -1 );
  }
  slapi_log_error( SLAPI_LOG_PLUGIN, extended_init , Plug-unsuccessfully registered.\n );
  return(0);
}
To add the plug-in configuration, use ldapmodify to add the entry. For example:
ldapmodify -a -D "cn=directory manager" -W -p 389 -h server.example.com -x

dn: cn=Test ExtendedOp,cn=plugins,cn=config
objectClass: top
objectClass: nsSlapdPlugin
objectClass: extensibleObject
cn: Test ExtendedOp
nsslapd-pluginPath: /path/to/test-plugin.so
nsslapd-pluginInitfunc: testexop_init
nsslapd-pluginType: extendedop
nsslapd-pluginEnabled: on
nsslapd-plugin-depends-on-type: database
nsslapd-pluginId: test-extendedop
nsslapd-pluginarg0: 1.2.3.4
Alternatively, shut down the server, add the plug-in parameters to the dse.ldif file, and restart the server.
Check out the testextendedop.c source file has for an example plug-in function that implements an extended operation. Example files are installed in install_directory/ldapserver/ldap/servers/plugins.

10.4. Specifying Start and Close Functions

For each extended operation plug-in, you can specify the name of a function to be called after the server starts and before the server is shut down.
Use the following parameters to specify these functions:
  • SLAPI_PLUGIN_START_FN — Specifies the function called after the Directory Server starts.
  • SLAPI_PLUGIN_CLOSE_FN — Specifies the function called before the Directory Server shuts down.

Chapter 11. Writing Matching Rule Plug-ins

This chapter explains how to write plug-in functions that handle matching rules.

11.1. Understanding Matching Rules

A matching rule specifies how one or more attributes of a particular syntax should be compared against assertion values. For example, a matching rule that specifies a sound-alike comparison attempts to match values that sound like the specified value. Each matching rule is identified by a unique OID (for example, 1.2.3.4).
LDAPv3 clients can specify a matching rule as part of a search filter in a search request. This type of search filter is called an extensible match filter.

11.1.1. Extensible Match Filters

In an extensible match filter, the client specifies that it wants to use the matching rule to compare a specified value against the values of entries in the directory. (For example, an extensible match filter might find all entries in which the sn attribute sounds like melon.)
An extensible match filter contains the following information:
  • The OID of the matching rule or the attribute type that you want to search (or both).
  • The value for which to search.
  • A preference indicating whether to also search the attributes in the DN.
For example, if the OID 1.2.3.4 identifies a matching rule that performs sounds like matches, the following extensible match filter attempts to find entries where the mail attribute sounds like moxie: (mail:1.2.3.4:=moxie)
In the search filter, the client can specify the OID that identifies a matching rule, and the attribute type. This indicates that the value in the filter should be compared against the attribute using the matching rule.
For example, if the OID 1.2.3.4 specifies a sound-alike match and if the string representation of the search filter is (uid:1.2.3.4:=moxie), it indicates that the client wants to find entries in which the value of the uid attribute sounds like moxie.
Although the LDAPv3 standard allows clients to omit the OID or the attribute type, at this time, the Red Hat Directory Server only supports extensible match filters that specify both the OID and attribute type.
The filter can also specify a preference indicating whether to include DN attributes in the search. For example, if the OID 1.2.3.4 specifies a sound-alike match and if the string representation of the search filter is (sn:dn:1.2.3.4:=moxie), it indicates that the client wants to find all entries in which the value of the sn attribute or the attributes in the DN (for example, uid, cn, ou, or o) sound like moxie.

11.1.2. Extensible Match Filters in the Directory Server

Directory Server already includes support for certain matching rules, which are used to determine the collation order and operator for searches of international data.
You can enable the Directory Server to handle your own matching rules for extensible match searches by defining your own matching rules plug-ins and registering them with the server.
You can also build indexes to improve the performance of search operations that use extended match filters.

11.2. Understanding Matching Rule Plug-ins

A matching rule plug-in can create filters that the server can use when handling extensible search filters. A matching rule plug-in can also create indexes to index entries for extensible searches.

11.2.1. Functions Defined in Matching Rule Plug-ins

The matching rule plug-in consists of the following:
  • An indexer function. [Optional].
  • A filter function.
  • A filter function that uses the index to speed up searches. [Optional].
  • A function to destroy a filter. [Optional].
  • A function to destroy an indexer. [Optional].
  • A factory function to create filters.
  • A factory function to create indexers. [Optional].
  • A close function to clean up before server shutdown. [Optional].
  • An initialization function to register the factory functions and the close function.
When the server starts and loads the matching rule plug-in, it calls the initialization function. In this function, you pass the server the pointers to the factory functions and the close function. The server calls these functions when needed. Refer to Section 11.2.2, “How Matching Rules Are Identified”, and Section 11.2.3, “How the Server Associates Plug-ins with OIDs”, for details.

11.2.2. How Matching Rules Are Identified

Matching rules are identified by OID. When the server encounters an OID in the following situations, it attempts to find the matching rule plug-in that handles the matching rule with that OID.
The server can encounter a matching rule OID in the following situations:
  • When reading in the server configuration file, the server may encounter an index directive that specifies the OID of the matching rule. For example:
    index attribute_name filter_type matching_rule_oid
    If the OID is associated with a matching rule plug-in, the server adds this OID to the list of matching rule OIDs to use for indexing.
    For information on setting up the server to index based on matching rule, refer to Section 11.3, “Indexing Based on Matching Rules”.
  • The server may receive an LDAP search request with an extensible match filter specifying the OID of the matching rule. For example, a string representation of an extensible match filter might be:
    (sn:dn:1.2.3.4:=Jensen)
    The search filter above specifies that the server should use the matching rule identified by the OID 1.2.3.4 to search for the value Jensen in the sn attribute and in all attributes in the DN.
    For information on setting up the server to handle extensible match filters, refer to Section 11.4, “Handling Extensible Match Filters”.
  • The server may receive an LDAP search request containing a sorting control, and the sorting control specifies the OID of the matching rule.
    For information on setting up the server to sort based on matching rules, refer to Section 11.5, “Handling Sorting by Matching Rules”.
In all of these situations, the server uses the matching rule OID to find the plug-in responsible for handling the rule. Refer to Section 11.2.3, “How the Server Associates Plug-ins with OIDs”, for details.

11.2.3. How the Server Associates Plug-ins with OIDs

The server associates plug-ins with OIDs using the following process:
  • When the server encounters the OID for a matching rule, it attempts to find the plug-in associated with that matching rule.
  • If no plug-in is associated with the matching rule, the server calls each matching rule plug-in to find one that handles the specified matching rule.
  • When the server finds a plug-in that handles the matching rule, the server creates an association between the plug-in and the matching rule OID for future reference.
  • If no matching rule plug-in supports the specified OID, the server returns an LDAP_UNAVAILABLE_CRITICAL_EXTENSION error to the client.

11.2.3.1.  Finding a Plug-in for Indexing

To determine which matching rule plug-in is responsible for indexing an attribute with a given matching rule (based on its OID), the server does the following for each plug-in:
  1. In a new Slapi_PBlock parameter block, the server sets the OID in the SLAPI_PLUGIN_MR_OID parameter.
  2. The server then calls the indexer factory function (specified in the SLAPI_PLUGIN_MR_INDEXER_CREATE_FN parameter) for the plug-in.
  3. The server then checks the SLAPI_PLUGIN_MR_INDEX_FN parameter.
    • If the parameter is NULL, the plug-in does not handle the matching rule specified by that OID.
    • If the parameter returns an indexer function, this plug-in handles the matching rule specified by that OID.
  4. Finally, the server frees the parameter block from memory.
At some point, the server may also call the indexer destructor function (specified in the SLAPI_PLUGIN_MR_DESTROY_FN parameter) to free the indexer object that was created by the indexer factory function.

11.2.3.2.  Finding a Plug-in for Searching

To determine which matching rule plug-in is responsible for handling an extensible match filter for a given matching rule (based on its OID), the server does the following for each plug-in:
  1. In a new Slapi_PBlock parameter block, the server sets the following parameters:
    • Sets the OID in the SLAPI_PLUGIN_MR_OID parameter.
    • Sets the type (from the filter) in the SLAPI_PLUGIN_MR_TYPE parameter.
    • Sets the value (from the filter) in the SLAPI_PLUGIN_MR_VALUE parameter.
  2. The server then calls the filter factory function (specified in the SLAPI_PLUGIN_MR_FILTER_CREATE_FN parameter) for the plug-in.
  3. The server checks the SLAPI_PLUGIN_MR_FILTER_MATCH_FN parameter.
    • If the parameter is NULL, the plug-in does not handle the matching rule specified by that OID.
    • If the parameter returns a filter matching function, this plug-in handles the matching rule specified by that OID.
  4. Finally, the server gets the following information from the plug-in for future use:
    • The filter index function specified in the SLAPI_PLUGIN_MR_FILTER_INDEX_FN parameter.
    • The value specified in the SLAPI_PLUGIN_MR_FILTER_REUSABLE parameter.
    • The filter reset function specified in the SLAPI_PLUGIN_MR_FILTER_RESET_FN parameter.
    • The filter object specified in the SLAPI_PLUGIN_OBJECT parameter.
    • The filter destructor function specified in the SLAPI_PLUGIN_DESTROY_FN parameter.
Information specified in the filter object is used by both the filter index function and the filter matching function.

11.2.4. How the Server Uses Parameter Blocks

The server uses parameter blocks as a means to pass information to and from plug-in functions.
When calling your matching rule plug-in functions, the server creates a new parameter block, set some input parameters, and pass the parameter block to your function. After retrieving output parameters from the block, the server typically frees the parameter block from memory.
In general, you should not expect a parameter block to be passed between plug-in functions. The value of a parameter set by one plug-in function may not necessarily be accessible to other plug-in functions, because each function is usually passed a new and different parameter block.

11.3. Indexing Based on Matching Rules

This section explains how to set up the server to index entries using a matching rule.

Note

You also need to define an initialization function to register your indexer factory function.

11.3.1. How the Server Sets Up the Index

When the server encounters a matching rule OID in an index directive in the server configuration file, the server determines which plug-in supports the matching rule identified by the OID. Refer to Section 11.2.3, “How the Server Associates Plug-ins with OIDs”, for details.
The server gets the OID returned in the SLAPI_PLUGIN_MR_OID parameter and associates this OID with the rest of the attribute indexing information (for example, the attribute type and the type of index) for future reference.
When adding, modifying, or deleting the values of an attribute, the server checks this information to determine if the attribute is indexed. Refer to Section 11.3.2, “How the Server Updates the Index”, for information on how attributes are indexed.

11.3.2. How the Server Updates the Index

When a value is added, modified, or removed from an attribute in an entry (or when the RDN of an entry is changed), the server performs the following tasks if that attribute has an index that uses matching rules:
  1. In a new Slapi_PBlock parameter block, the server sets the following parameters:
    • Sets the OID in the SLAPI_PLUGIN_MR_OID parameter.
    • Sets the attribute type (of the value being added, modified, or removed) in the SLAPI_PLUGIN_MR_TYPE parameter.
  2. Next, the server calls the indexer factory function (specified in the SLAPI_PLUGIN_MR_INDEXER_CREATE_FN parameter) for the plug-in to create the indexer object.
  3. The server generates the index keys for the values to be added or deleted:
    • The server first verifies that the SLAPI_PLUGIN_MR_INDEX_FN parameter specifies an indexer function and the SLAPI_PLUGIN_MR_OID parameter specifies the official OID of the matching rule.
    • If these are both set, the server sets the SLAPI_PLUGIN_MR_VALUES parameter to the array of berval structures containing the new or modified values that need to be indexed and calls the indexer function.
    • Next, the server gets the value of the SLAPI_PLUGIN_MR_KEYS parameter, which is an array of berval structures containing the keys corresponding to the values.
  4. The server inserts or deletes the keys and values in the index for that attribute.
  5. The server calls the indexer destructor function (specified in the SLAPI_PLUGIN_MR_DESTROY_FN parameter) to free the indexer object.
At the end of the process, the server frees any parameter blocks that were allocated during the process.

11.3.3. Writing the Indexer Factory Function

The indexer factory function takes a single Slapi_PBlock argument. This function should be thread-safe. The server may call this function concurrently.
The indexer factory function should perform the following tasks:
  1. Get the OID from the SLAPI_PLUGIN_MR_OID parameter, and determine whether that OID is supported by your plug-in.
    • If the OID is not supported, you need to return the result code LDAP_UNAVAILABLE_CRITICAL_EXTENSION.
    • If the OID is supported, continue with this process.
  2. Get the value of the SLAPI_PLUGIN_MR_USAGE parameter. This parameter should have one of the following values:
    • If the value is SLAPI_PLUGIN_MR_USAGE_SORT, the server is calling your function to sort search results. Refer to Section 11.5, “Handling Sorting by Matching Rules”, for more information.
    • If the value is SLAPI_PLUGIN_MR_USAGE_INDEX, the server is calling your function to index an entry.
    You can use this information to set different information in the indexer object or to set a different indexer function, based on whether the function is being called to index or to sort.
  3. You can also get any data that you set in the SLAPI_PLUGIN_PRIVATE parameter during initialization. (Refer to Section 11.7, “Writing an Initialization Function”.)
  4. Create an indexer object containing any information that you want to pass to the indexer function.
  5. Set the following parameters:
    • Set the SLAPI_PLUGIN_MR_OID parameter to the official OID of the matching rule (if the value of that parameter is not the official OID).
    • Set the SLAPI_PLUGIN_OBJECT parameter to the indexer object.
    • Set the SLAPI_PLUGIN_MR_INDEX_FN parameter to the indexer function. (Refer to Section 11.3.5, “Writing the Indexer Function”.)
    • Set the SLAPI_PLUGIN_DESTROY_FN parameter to the function responsible for freeing any memory allocated by the factory function, such as the indexer object. refer to Section 11.3.3, “Writing the Indexer Factory Function”, for details.
  6. Return 0 (or the result code LDAP_SUCCESS) if everything completed successfully.

11.3.4. Getting and Setting Parameters in Indexer Factory Functions

The following table summarizes the different parameters that the indexer factory function should get and set in the parameter block that is passed in.

Table 11.1. Input and Output Parameters Available to an Indexer Factory Function

Parameter Name Data Type Description
SLAPI_PLUGIN_MR_OID char * Input parameter. Matching rule OID (if any) specified in the index directive.
SLAPI_PLUGIN_MR_TYPE char * Input parameter. Attribute type (if any) specified in the index directive.
SLAPI_PLUGIN_MR_USAGE unsigned int Input parameter. Specifies the intended use of the indexer object. This parameter can have one of the following values:
  • SLAPI_PLUGIN_MR_USAGE_INDEX specifies that the indexer object should be used to index entries.
  • SLAPI_PLUGIN_MR_USAGE_SORT specifies that the indexer object should be used to sort entries.
You can use this to specify different information in the indexer object or different indexer functions, based on whether the plug-in is used for indexing or sorting. For information on sorting search results, refer to Section 11.5, “Handling Sorting by Matching Rules”.
SLAPI_PLUGIN_PRIVATE void * Input parameter. Pointer to any private data originally specified in the initialization function. Refer to Section 11.7, “Writing an Initialization Function”, for details.
SLAPI_PLUGIN_MR_OID char * Output parameter. Official matching rule OID of the index.
SLAPI_PLUGIN_MR_INDEX_FN void * (function pointer) Output parameter. Name of the function called by the server to generate a list of keys used for indexing a set of values.
SLAPI_PLUGIN_DESTROY_FN void * (function pointer) Output parameter. Name of the function to be called to free the indexer object.
SLAPI_PLUGIN_OBJECT void * Output parameter. Pointer to the indexer object created by your factory function.

11.3.5. Writing the Indexer Function

The indexer function takes a single Slapi_PBlock argument. This function will never be called for the same indexer object concurrently. (If you plan to manipulate global variables, remember that the server can call this function concurrently for different indexer objects.)
The indexer function should perform the following tasks:
  1. Get the values of the following parameters:
    • Get the indexer object from the SLAPI_PLUGIN_OBJECT parameter (if the parameter is set).
    • Get the array of values that you want indexed from the SLAPI_PLUGIN_MR_VALUES parameter.
  2. Generate index keys for these values, and set the SLAPI_PLUGIN_MR_KEYS parameter to the array of these keys.
  3. Return 0 (or the result code LDAP_SUCCESS) if everything completed successfully.
The server adds or removes the keys and the corresponding values from the appropriate indexes.

11.3.6. Getting and Setting Parameters in Indexer Functions

The following table summarizes the different parameters that the indexer function should get and set in the parameter block that is passed in.

Table 11.2. Input and Output Parameters Available to an Indexer Function

Parameter Name Data Type Description
SLAPI_PLUGIN_MR_VALUES struct berval ** Input parameter. Pointer to an array of berval structures containing the values of the entry's attributes that need to be indexed.
SLAPI_PLUGIN_OBJECT void * Input parameter. Pointer to the indexer object created by the indexer factory function. Refer to Section 11.3.3, “Writing the Indexer Factory Function”, for details.
SLAPI_PLUGIN_MR_KEYS struct berval ** Output parameter. Keys generated for the values specified in the SLAPI_PLUGIN_MR_VALUES parameter. The server creates indexes using these keys.

11.4. Handling Extensible Match Filters

This section explains how to set up the server to process searches that use extensible match filters (matching rules).

Note

You also need to define an initialization function to register your filter factory function.

11.4.1. How the Server Handles the Filter

When the server processes a search request that has an extensible match filter, the server performs the following tasks:
  1. First, the server finds the plug-in associated with this OID, if an association between the OID and plug-in has already been made.
    If no association has been made, the server attempts to find a matching rule plug-in that handles the OID. Refer to Section 11.2.3, “How the Server Associates Plug-ins with OIDs”, for details.
  2. The server then attempts to generate a list of search result candidates from the indexes. In a new Slapi_PBlock parameter block:
    1. The server puts the filter object in the SLAPI_PLUGIN_OBJECT parameter and calls the filter index function (specified in the SLAPI_PLUGIN_MR_FILTER_INDEX_FN parameter).
    2. The server checks the value of the SLAPI_PLUGIN_MR_QUERY_OPERATOR parameter. If the operator is a known type (such as SLAPI_OP_EQUAL), the server will use the operator when searching the index for candidates. For details, refer to Section 11.4.2, “Query Operators in Matching Rules”.
    3. The server sets the SLAPI_PLUGIN_MR_VALUES parameter to each of the values specified in the filter and calls the indexer function (which is specified in the SLAPI_PLUGIN_MR_INDEX_FN parameter) to generate the key (specified in the SLAPI_PLUGIN_MR_KEYS parameter).
    4. The server uses the keys and the query operator to find potential candidates in the indexes.
    The server considers all entries to be potential candidates if at least one of the following is true:
    • The matching rule plug-in has no indexer function (specified in the SLAPI_PLUGIN_MR_INDEX_FN parameter).
    • No index applies to the search (for example, if the query operator does not correspond to an index).
    • No keys are generated for the specified values.
  3. For each candidate entry, the server performs the following tasks to determine if the entry matches the search filter:
    1. The server calls the filter matching function (which is specified in the SLAPI_PLUGIN_MR_FILTER_MATCH_FN parameter), passing in the filter object, the entry, and the attributes of the entry.
    2. If the entry does not match, but the search request also specifies that the attributes in the DN should be searched, the server calls the filter matching function again, passing in the filter object, the entry, and the attributes in the DN.
  4. The server then checks the value returned by the filter matching function:
    • If the function returns 0, the entry matched the search filter.
    • If the function returns -1, the entry did not match the search filter.
    • If the function returns an LDAP error code (a positive value), an error occurred.
  5. If the entry matches the filter, the server verifies that the entry is in the scope of the search before returning the entry to the LDAP client as a search result.

11.4.2. Query Operators in Matching Rules

As discussed in Section 11.4.1, “How the Server Handles the Filter”, the server uses a query operator when searching the index for possible candidates.
This applies to the ldbm default backend database. If you are using your own back-end or if you have not set up indexing by matching rules, the server does not make use of the query operator.
The server checks the value of the SLAPI_PLUGIN_MR_QUERY_OPERATOR parameter to determine which operator is specified. The following table lists the possible values for this parameter.

Table 11.3. Query Operators in Extensible Match Filters

Operator Description
SLAPI_OP_LESS <
SLAPI_OP_LESS_OR_EQUAL <=
SLAPI_OP_EQUAL =
SLAPI_OP_GREATER_OR_EQUAL >=
SLAPI_OP_GREATER >
If the query operator is SLAPI_OP_EQUAL, the server attempts to find the keys in the index that match the value specified in the search filter. In the case of the other query operators, the server attempts to find ranges of keys that match the value.

11.4.3. Writing a Filter Factory Function

The filter factory function takes a single Slapi_PBlock argument. This function should be thread-safe. The server may call this function concurrently. (Each incoming LDAP request is handled by a separate thread. Multiple threads may call this function if processing multiple requests that have extensible match filters.)
file:///home/joakes/svn/8.0/Plugin_Programming_Guide/tmp/en-US/html/Plugin_Programming_Guide-Handling_Extensible_Match_Filters-Getting_and_Setting_Parameters_in_Filter_Factory_Functions.html The filter factory function should perform the following tasks:
  1. Get the OID from the SLAPI_PLUGIN_MR_OID parameter and determine whether that OID is supported by your plug-in.
    • If the OID is not supported, you need to return the result code LDAP_UNAVAILABLE_CRITICAL_EXTENSION. The server will send this back to the client.
    • If the OID is supported, continue with this process.
  2. Get and check the values of the SLAPI_PLUGIN_MR_TYPE and SLAPI_PLUGIN_MR_VALUE parameters.
    The values of these parameters are the attribute type and value specified in the extensible match filter.
  3. You can also get any data that you set in the SLAPI_PLUGIN_PRIVATE parameter during initialization. Refer to Section 11.7, “Writing an Initialization Function”.
  4. Create a filter object, and include the following information:
    • The official OID of the matching rule. [Optional].
    • The attribute type specified in the filter.
    • The value specified in the filter.
    • Any additional data that you want made available to the filter index function (for example, the query operator, if specified in the filter).
    The server will call your filter index function at a later time to extract this information from the filter object.
  5. Set the following parameters:
  6. Return 0 (or the result code LDAP_SUCCESS) if everything completed successfully.

11.4.4. Getting and Setting Parameters in Filter Factory Functions

The following table summarizes the different parameters that the filter factory function should get and set in the parameter block that is passed in.

Table 11.4. Input and Output Parameters Available to a Filter Factory Function

Parameter Name Data Type Description
SLAPI_PLUGIN_MR_OID char * Input parameter. Matching rule OID (if any) specified in the extensible match filter.
SLAPI_PLUGIN_MR_TYPE char * Input parameter. Attribute type (if any) specified in the extensible match filter.
SLAPI_PLUGIN_MR_VALUE struct berval * Input parameter. Value specified in the extensible match filter.
SLAPI_PLUGIN_PRIVATE void * Input parameter. Pointer to any private data originally specified in the initialization function. Refer to Section 11.7, “Writing an Initialization Function”, for details.
SLAPI_PLUGIN_MR_FILTER_MATCH_FN mrFilterMatchFn (function pointer) Output parameter. Name of the function called by the server to match an entry's attribute values against the value in the extensible search filter.
SLAPI_PLUGIN_MR_FILTER_INDEX_FN void * (function pointer) Output parameter. Name of the function called by the server to generate a list of keys used for indexing a set of values.
SLAPI_PLUGIN_DESTROY_FN void * (function pointer) Output parameter. Name of the function to be called to free the filter object.
SLAPI_PLUGIN_OBJECT void * Output parameter. Pointer to the filter object created by your factory function.

11.4.5. Writing a Filter Index Function

The filter index function takes a single Slapi_PBlock argument. This function will never be called for the same filter object concurrently. (If you plan to manipulate global variables, remember that the server can call this function concurrently for different filter objects.)
The filter index function should perform the following tasks:
  1. Get the filter object from the SLAPI_PLUGIN_OBJECT parameter (if the parameter is set).
  2. Using data from the object, determine and set the values of the following parameters:
    • SLAPI_PLUGIN_MR_OID - Set to the official OID of the matching rule.
    • SLAPI_PLUGIN_MR_TYPE - Set to the attribute type in the filter object.
    • SLAPI_PLUGIN_MR_VALUES - Set to the values in the filter object.
    • SLAPI_PLUGIN_MR_QUERY_OPERATOR - Set to the query operator that corresponds to this search filter. Refer to Section 11.4.2, “Query Operators in Matching Rules”, for possible values for this parameter.
    • SLAPI_PLUGIN_OBJECT - Set to the filter object.
    • SLAPI_PLUGIN_MR_INDEX_FN - Set to the indexer function. Refer to Section 11.3.5, “Writing the Indexer Function”.
  3. Return 0 (or the result code LDAP_SUCCESS) if everything completed successfully.

11.4.6. Getting and Setting Parameters in Filter Index Functions

The following table summarizes the different parameters that the filter index function should get and set in the parameter block that is passed in.

Table 11.5. Input and Output Parameters Available to a Filter Index Function

Parameter Name Data Type Description
SLAPI_PLUGIN_OBJECT void * Input and Output parameter. Pointer to the filter object created by the factory function. For details, refer to Section 11.4.3, “Writing a Filter Factory Function”.
SLAPI_PLUGIN_MR_QUERY_OPERATOR int Output parameter. Query operator used by the server to determine how to compare the keys generated from SLAPI_PLUGIN_MR_VALUES and SLAPI_PLUGIN_MR_INDEX_FN against keys in the index. For a list of possible values for this parameter, refer to Section 11.4.2, “Query Operators in Matching Rules”.
SLAPI_PLUGIN_MR_OID char * Output parameter. Official matching rule OID (if any) specified in the extensible match filter.
SLAPI_PLUGIN_MR_TYPE char * Output parameter. Attribute type (if any) specified in the extensible match filter.
SLAPI_PLUGIN_MR_VALUES struct berval ** Output parameter. Pointer to an array of berval structures containing the values specified in the extensible match filter.
SLAPI_PLUGIN_MR_INDEX_FN void * (function pointer) Output parameter. Name of the function called by the server to generate a list of keys used for indexing a set of values.

11.4.7. Writing a Filter Matching Function

The filter matching function has the following prototype:
#include slapi-plugin.h
typedef int (*mrFilterMatchFn) (void* filter, Slapi_Entry* entry, Slapi_Attr* attrs);
This function passes the following arguments:
  • filter is a pointer to the filter object.
  • entry is a pointer to the Slapi_Entry entry that should be compared against the filter.
  • attrs is the first Slapi_Attr attribute in the entry or in the set of DN attributes. (The extensible match filter might specify that the attributes in the DN of an entry should also be included in the search.)
This function will never be called for the same filter object concurrently. (If you plan to manipulate global variables, remember that the server can call this function concurrently for different filter objects.)
The filter matching function should perform the following tasks:
  1. From the filter object, get the attribute type, the values, and the query operator.
  2. Find the corresponding attribute in the attributes passed into the function. Remember to search for subtypes of an attribute (for example, cn=lang-ja) in the filter and in the attributes specified by attrs.
    You can call the slapi_attr_type_cmp() function to compare the attribute in the filter against the attributes passed in as arguments.
  3. Using the query operator to determine how the values should be compared, compare the values from the filter against the values in the attribute.
  4. Return one of the following values:
    • 0 if the values of the attribute match the value specified in the filter.
    • -1 if the values do not match.
    • An LDAP error code (a positive number) if an error occurred.

11.5. Handling Sorting by Matching Rules

If you have set up indexing by a matching rule, you can also sort search results by that matching rule. The server can use the keys in the index to sort the search results.
When processing a request to sort by a matching rule, the server does the following:
  1. In a new Slapi_PBlock parameter block, the server sets the following parameters:
    • Sets the OID in the SLAPI_PLUGIN_MR_OID parameter.
    • Sets the attribute type (of the value being added, modified, or removed) in the SLAPI_PLUGIN_MR_TYPE parameter.
    • Sets the SLAPI_PLUGIN_MR_USAGE parameter to SLAPI_PLUGIN_MR_USAGE_SORT. (This indicates that the created indexer object will be used for sorting, not indexing.)
  2. The server then calls the indexer factory function (specified in the SLAPI_PLUGIN_MR_INDEXER_CREATE_FN parameter) for the plug-in.
  3. The server generates the index keys for the values to be sorted:
    • The server sets the SLAPI_PLUGIN_MR_VALUES parameter to the array of berval structures containing the values to be sorted.
    • The server calls the indexer function (specified by the SLAPI_PLUGIN_MR_INDEXER_FN parameter).
    • The server then gets the value of the SLAPI_PLUGIN_MR_KEYS parameter, which is an array of berval structures containing the keys corresponding to the values.
  4. The server compares the keys to sort the results.

11.6. Writing a Destructor Function

The server calls the destructor function to free any memory that was allocated; for example, to the indexer object or the filter object.
The destructor function takes a single Slapi_PBlock argument. The following table summarizes the different parameters that the destructor function should get and set in the parameter block that is passed in.

Table 11.6. Input and Output Parameters Available to a Destructor Function

Parameter Name Data Type Description
SLAPI_PLUGIN_OBJECT void * Input parameter. Pointer to the filter object or indexer object created by your factory function.
For example, your destructor function can get the indexer object from the SLAPI_PLUGIN_OBJECT parameter and free the object from memory.
This function will never be called for the same indexer or filter object concurrently. (If you plan to manipulate global variables, remember that the server can call this function concurrently for different filter or indexer objects.)

11.7. Writing an Initialization Function

Internally, the server keeps a list of matching rule plug-ins. When dealing with matching rules, the server attempts to find the matching rule plug-in to handle the given matching rule. Refer to Section 11.2.3, “How the Server Associates Plug-ins with OIDs”, for details.
In order to add your plug-in to that internal list, you need to write an initialization function. The initialization function takes a single Slapi_PBlock argument. The function should set the following parameters:
You need to register the initialization function so that the server runs the function when starting. For how to register matching rule functions, refer to Section 11.8, “Registering Matching Rule Functions”.
The following table summarizes the different parameters that the initialization function should get and set in the parameter block that is passed in.

Table 11.7. Input and Output Parameters Available to a Matching Rule Plug-in Initialization Function

Parameter Name Data Type Description
SLAPI_PLUGIN_ARGC int Input parameter. Number of arguments in the plugin directive, not including the library name and initialization function name.
SLAPI_PLUGIN_ARGV char ** Input parameter. Array of string arguments in the plugin directive, not including the library name and initialization function name.
SLAPI_PLUGIN_MR_FILTER_CREATE_FN void * (function pointer) Output parameter. The factory function used for creating filters.
SLAPI_PLUGIN_MR_INDEXER_CREATE_FN void * (function pointer) Output parameter. The factory function used for creating indexers.
SLAPI_PLUGIN_CLOSE_FN void * (function pointer) Output parameter. The close function, which the server calls before shutting down.
SLAPI_PLUGIN_PRIVATE void * Output parameter. Pointer to any private data you want passed to your plug-in functions.

11.8. Registering Matching Rule Functions

Depending on the Directory Server version, add the appropriate information for your plug-in function.
In current releases of Directory Server, shut down the server, add the plug-in parameters to the dse.ldif file, and restart the server. Refer to Chapter 3, Configuring Plug-ins.
For example, your plug-in entry might appear as follows:
dn: cn=Test MatchineRule,cn=plugins,cn=config
objectClass: top
objectClass: nsSlapdPlugin
objectClass: extensibleObject
cn: Test MatchingRule
nsslapd-pluginPath: libtest-plugin
nsslapd-pluginInitfunc: testmatchrule_init
nsslapd-pluginType: matchingRule
nsslapd-pluginEnabled: on
nsslapd-pluginId: test-matchingrule
nsslapd-pluginarg0: /etc/dirsrv/slapd-instance_name/ 
customplugins/filename.conf

11.9. Specifying Start and Close Functions

For each matching rule operation plug-in, you can specify the name of a function to be called after the server starts and before the server is shut down. These functions take a single Slapi_PBlock argument.
The following table summarizes the different parameters that the initialization function should get and set in the parameter block that is passed in.

Table 11.8. Input and Output Parameters Available to a Matching Rule Plug-in Initialization Function

Parameter Name Data Type Description
SLAPI_PLUGIN_START_FN void * (function pointer) Output parameter. The function called after the Directory Server starts up.
SLAPI_PLUGIN_CLOSE_FN void * (function pointer) Output parameter. The function called before the Directory Server shuts down.
If you register multiple plug-ins with different start and close functions, the functions are called in the order that the plug-ins are registered; in other words, in the order that the plugin directives appear in the server configuration file.

Chapter 12. Using the Custom Distribution Logic

The distribution plug-in provided with Red Hat Directory Server distributes a flat namespace, allowing you to associate several databases with a single suffix.

12.1. About Distributing Flat Namespaces

You can distribute entries located in a flat tree structure. Imagine you administer the directory for example.com, an ISP. The directory for example.com contains the following entries distributed in a flat tree structure:

Figure 12.1. 

Because the number of users is too large, you decide to distribute the entries according to the first letter of each user's last name, assigning each letter to a separate database. To do this, you need to create your own distribution function. Your function determines how each operation received by the ou=users suffix is routed to the database containing the information for a particular user.
After you have distributed entries, you cannot redistribute them. The following restrictions apply:
  • You cannot change your distribution function after you have deployed entry distribution.
  • You cannot use the ldapmodrdn operation to rename entries if the modification would cause them to be distributed into a different database.
  • You cannot use the ldapmodify operation to change entries if that would cause them to be distributed into a different database.
    For example, if you distribute entries according to their telephone number, you cannot change the telephone number attribute of an entry without breaking entry distribution.
  • After you have deployed entry distribution you cannot add more databases.

12.2. Creating a Distribution Function

Using the distribution function, you can set a suffix to have any number of database pointers. This allows you to distribute requests made to a suffix over a number of databases.
For example, the entry for the dc=example,dc=com suffix appears as follows:
dn: cn=dc=example,dc=com,cn=mapping tree,cn=config
objectclass: top
objectclass: extensibleObject
nsslapd-backend: example.com database A-M
nsslapd-backend: example.com database N-Z
When the suffix receives a request from a client, it uses the distribution function to determine which database services the operation. The plug-in consists of a function and a library. This function and library are part of the entry for the dc=example,dc=com suffix and appear as follows:
nsslapd-distribution-plugin: /path/to/a/shared/library
nsslapd-distribution-funct: distribution-function-name
Each time the server gets a request for a suffix that contains the distribution function, the function is called. The function then decides which database (backend) processes the request. The decision made by the function is based on some piece of information present in the pblock at the time of the request, such as the entry DN, a hash function, the time of day, or the type of operation.
For search operations, the function can forward the operation to a single database, or to all databases.
The distribution function itself appears as follows:
 int distribution_function(Slapi_PBlock *pb, Slapi_DN * dn, Slapi_Backend **mtn_be, int be_count, Slapi_DN * node_dn);
The following table lists the parameters taken by the distribution function:

Table 12.1. Distribution Function Parameters

Parameter Name Description
pb The pblock of the plug-in which contains all of the information about the operations in progress. This structure is the same as that for other plug-ins; for example, operation type, IP address of the client, target DN, search filter, bind credentials, etc.
mtn_be A table of size be_count containing the list of databases defined for the suffix. If a database is defined in the suffix entry but is not available, the corresponding pointer in the table will be set to NULL.
node_dn The suffix containing the distribution function.
be_count The size of the table that contains the list of databases involved in the distribution of entries.
int The row number of the database in the mtn_be table. For search operations, you can return a value of MTN_ALL_BACKENDS to specify that all databases must be searched.
The root entry for the suffix must be present in each database in order for the distribution function to work properly. For example, for the suffix dc=example,dc=com, you need to create an entry corresponding to dc=example,dc=com in each database involved in the distribution.
You can create the root entry in two ways:
  • Import the same LDIF file into each database using the ldif2db command-line utility.
    This LDIF file should contain the root entry as well as data that you want to distribute across the databases. Only the data determined by the distribution function to be appropriate for each database will be imported.
  • Create an LDIF file that contains the root entry. You can do this by exporting the root entry (for example, dc=example,dc=com) in LDIF format using the ldapsearch command-line utility.
    You then need to import the LDIF file into each database using the ldif2db command-line utility. If you have three databases for a single suffix, you need to import the suffix entry three times.
When a subtree search is performed above a suffix that is distributed among several databases, the search will be performed on all databases. This means that the shared suffix entry that you create on each database (in the example, dc=example,dc=com) can be returned multiple times.

12.3. Adding the Distribution Function to Your Directory

To declare the distribution function to your directory, you need to add multiple databases to a single suffix and then declare the distribution function in the suffix.
These procedures assume you have already created a suffix and associated it with a single database. For the procedure on creating a new suffix and database, refer to the Creating Directory Entries chapter in the Red Hat Directory Server Administrator's Guide.

Note

You need to add all of the databases required for your distribution algorithm before you deploy entry distribution. You cannot add more databases later without changing the algorithm. Whenever you install new distribution functions, ensure that you restart the Directory Server. Otherwise, the new libraries will not be loaded properly.

12.3.1. Adding Multiple Databases to a Single Suffix

12.3.1.1. Using the Console

The following procedure describes how to add multiple databases to a suffix using the Console.
  1. In the Directory Server Console, select the Configuration tab.
  2. Expand the Data tree, and select the suffix to which you want to add another database.
  3. From the Object menu, select New Database. You can also right click the suffix and select New Database from the menu.
    The Create New Database dialog box appears.
  4. Enter the name of the newdatabase in the Database Name field.
  5. In the Create database in field, enter the path to the location where the data for your new database will be stored.
    You can also click Browse to locate the path on your local machine.
  6. Click OK to save your changes.
A warning message displays telling you to declare a distribution function in the suffix. The next procedure describes how to declare the function in a suffix.

12.3.1.2. Using the Command-Line

The following procedure describes how to add multiple databases to a suffix using the command-line.
  1. Use the ldapmodify command-line utility to add another database to your directory configuration file. The database configuration information is stored in the cn=ldbm database,cn=plugins,cn=config entry.
    For example, to add a new database to the server example1, you add a new entry to the configuration file by performing an ldapmodify as follows:
    ldapmodify -a -D "cn=directory manager" -W -p 389 -h server.example.com -x
    The ldapmodify utility binds to the server and prepares it to add an entry to the configuration file.
  2. Create the entry for the new database as follows:
    dn: cn=Data2,cn=ldbm database,cn=plugins,cn=config
    objectclass: extensibleObject
    objectclass: nsBackendInstance
    nsslapd-suffix: ou=people,dc=example,dc=com
    
    The entry added corresponds to a database named Data2 that contains the data for the root suffix ou=people,dc=example,dc=com.
    The database name, given in the DN attribute, must correspond with one of the values in the nsslapd-backend attribute of the suffix entry.

12.3.2. Adding Distribution Logic to a Suffix

The distribution logic is a function declared in a suffix. This function is called for every operation reaching this suffix, including the subtree search operations that start above the suffix. You can add a distribution function to a suffix using both the Console and the command-line.

12.3.2.1.  Using the Console

To use the Console to add a distribution function to a suffix:
  1. In the Directory Server Console, select the Configuration tab.
  2. Expand the Data tree, and select the suffix to which you want to add the distribution function.
  3. Select the Databases tab in the right pane.
  4. Click Add to add new databases to the suffix from the Database List.
  5. Enter the path to the distribution library in the Distribution Library field, or click Browse to locate the library on your local machine.
  6. Enter the name of your distribution function in the Function Name field.
  7. Click Save to save your changes.

12.3.2.2.  Using the Command-Line

To use the Command-line to add a distribution function to a suffix:
Use the ldapmodify command-line utility to add the following lines to the suffix entry:
nsslapd-distribution-plugin: path_to_shared_library
nsslapd-distribution-funct: distribution_function_name
The first line provides the name of the library that your plug-in uses. The second line provides the name of the distribution function itself.

12.4. Using the Distribution Logic Examples

The directory provides three distribution logic examples. The examples illustrate the following:
  • Distributing entries based on the first letter of their RDN (alpha_distribution).
    The example uses as many databases as you like to contain the data. For example, if you create three databases for a single suffix, entries starting with the letters A-I go to database 0, entries starting with the letters J-R go to database 1, and entries starting with the letters S-Z go to database 2. If you create 26 databases, each database would receive the entries for one letter of the alphabet.
  • Distributing entries based on a simple hash algorithm (hash_distribution).
    In this example, entries are randomly distributed using a hash algorithm on the RDN to compute the database to which the entry will be written.
  • Chaining entries to a read-write replica from a read-only replica (chaining_distribution).
    Usually the directory returns a referral to clients making update requests to a read-only replica. This example uses a distribution function on a suffix that contains both a read-only database and a database link. When the read-only database receives an update request, it forwards the request using the database link to a read-write database. The database link needs to be configured to chain on update.
    For information on configuring database links, refer to the Creating Directory Entries chapter in the Red Hat Directory Server Administrator's Guide.
The following directory contains the uncompiled C code examples: install_directory//ldapserver/ldap/servers/slapd/
This directory contains the distrib.c file, which contains three example functions (alpha_distribution, hash_distribution, and chaining_distribution) and a Makefile for compiling them.
After you have compiled the source code, there is a distrib-plugin.so.
For example, to use the hash distribution function:
  1. Create a suffix.
  2. Create several databases under that suffix.
  3. Import the suffix entry to each of the databases you created.
  4. Add the following lines to the suffix:
    nsslapd-distribution-plugin: /plugin/distrib-plugin.so
    nsslapd-distribution-funct: hash_distribution
    

12.5. Custom Distribution Checklist

In summary, the following steps are involved in adding the distribution function to your directory:
  • Create the distribution function.
  • Create a suffix.
  • Add as many databases to the suffix as required by your distribution algorithm.
  • Declare the distribution function in the suffix. You must specify the library path and the function name.
  • Import data into the databases. If you do not import data, you need to import the root entry to each database.

Chapter 13. Using Data Interoperability Plug-ins

This chapter explains how to use the Data Interoperability (DIOP) feature of Red Hat Directory Server (Directory Server). The DIOP feature refers to Directory Server's ability to work with a proprietary database, instead of the default database created during installation.
You can now use the enhanced pre-operation interfaces to implement plug-ins that are designed to provide access to alternative directory data stores, instead of the database backend plug-in interface, which is not supported in current releases. You do this by developing a custom pre-operation plug-in to provide an alternate functionality for the LDAP operations, such as search, modify, add, and so on. These operations are generally targeted at the root suffix or the null DN (meaning dn:), and your plug-in will have to be designed to intercept these operations and divert them to be serviced by an alternate data source or alternate access methods.
This chapter covers deployment considerations, configuration changes required to use the DIOP feature, a list of supported and unsupported features, and other useful information.

13.1. Installing Directory Server

This section explains how to install Directory Server in order to test and use the DIOP feature.

13.1.1. Understanding Deployment Configuration

To verify whether the DIOP feature works in Directory Server, your deployment must comprise two instances of Directory Server:
  • An instance of Directory Server that will be used for storing configuration data. This instance is identified as the configurationDirectory Server.
  • An instance of Directory Server that will be used for enabling the DIOP plug-in. This instance is identified as the DIOP-enabledDirectory Server.
For detailed information on directory deployments, check the Red Hat Directory Server Deployment Guide. To understand the role of a configuration Directory Server in a directory deployment, check Managing Servers with Red Hat Console.
Because the DIOP plug-in is a pre-operation plug-in, enabling the plug-in will impose certain limitations on the default behavior of Directory Server.
  • The Directory Server Console will not be fully functional in the DIOP-enabled Directory Server, and you will not be able to administer the server via the Console. However, you will be able to use the configuration Directory Server Console to manage the DIOP-enabled Directory Server.
  • Some of the default plug-ins that are provided with the server will not work in the DIOP-enabled Directory Server. The DIOP plug-in is a pre-operation plug-in, and intercepting all LDAP operations will result in the other plug-ins being unusable. Table 13.1, “Plug-in Status in DIOP-Enabled Directory Server” identifies plug-ins that are unsupported in the DIOP-enabled Directory Server. All unsupported plug-ins must be disabled before using the DIOP plug-in.

Table 13.1. Plug-in Status in DIOP-Enabled Directory Server

Default Directory Server Plug-in Programmer's Guide (Names as they appear in the Directory Server Console) Unsupported Plug-ins (Indicated by X)
7-bit check X
ACL -
ACL preoperation -
Binary Syntax -
Boolean Syntax -
Case Exact String Syntax -
Case Ignore String Syntax -
chaining database X
Class of Service X
Country String Syntax -
Distinguished Name Syntax -
Generalized Time Syntax -
HTTP Client -
Integer Syntax -
Internationalization Plugin -
JPEG Syntax -
ldbm database -
Legacy Replication X
Multimaster Replication X
Octet String Syntax -
OID Syntax -
Pass-through Authentication X
Postal Address Syntax -
Referential Integrity Postoperation X
Retro Changelog X
Roles X
Space Insensitive Syntax -
State Change X
Telephone Syntax -
UID Uniqueness X
URI Syntax -
Views X
CLEAR -
CRYPT -
DES -
NS-MTA-MD5 -
SHA -
SSHA -
The figure below illustrates Directory Server deployment required for testing the DIOP feature.
A typical Directory Server Deployment

Figure 13.1. A typical Directory Server Deployment

In the above figure, slapd-<configInstance> is the configuration Directory Server and slapd-<diopInstance> is the Directory Server instance with the DIOPplug-in turned on.
  • The management and administration of slapd-<configInstance> is done via the corresponding Directory Server Console, accessible from within Red Hat Console.
  • The management and administration of slapd-<diopInstance> is done via the Directory Server Console of the slapd-<configInstance> instance. This is because the slapd-<diopInstance> instance does not support the full functionality of Red Hat Console.
To summarize the installation requirements for testing the DIOP feature:
  • You install two instances of Directory Server under the same server root (by specifying the same installation directory). For example, you can install two Directory Server instances:
/usr/lib64/dirsrv/slapd-<configInstance>
/usr/lib64/dirsrv/slapd-<diopInstance>
where /etc/dirsrv/slapd-instance_name is the default installation directory. In the sections that follow, the installation directory is identified as /etc/dirsrv/slapd-instance_name.
  • After you install the two instances, you designate the second Directory Server instance (slapd-<diopInstance>) for testing the DIOP feature.
  • You manage the first Directory Server instance (slapd-<configInstance>) using Red Hat Console and the corresponding Administration Server, which is running under the same server root.
  • You can indirectly manage the second Directory Server instance (slapd-<diopInstance>) through the first Directory Server instance (slapd-<configInstance>).
  • You disable the unsupported plug-ins in the second Directory Server instance (slapd-<diopInstance>).
For general information about installing Directory Server, refer to the accompanying Red Hat Directory Server Installation Guide. You can also find the documentation for Directory Server at https://access.redhat.com/documentation/en/

13.1.2. Installing Two Instances of Directory Server

Follow these instructions to create two instances of Directory Server:
  1. Read the installation-specific documents (Red Hat Directory Server Installation Guide and Release Notes), and verify that your system meets the requirements specified in the documentation. Ensure that all patches are installed.
  2. Unset the environment variable: unsetenv LD_LIBRARY_PATH
  3. Unpack the binaries.
  4. Run the setup program, and install an instance of Directory Server: slapd-<configInstance>.
  5. Start the Admin Server:
    service dirsrv-admin start
  6. Start the Directory Server Console:
    redhat-idm-console
  7. Use the Directory Server Console to create a second instance of Directory Server, slapd-diopInstance.
    In the navigation pane, select the Server Group, right click, select Create Instance of Red Hat Directory Server, and follow the prompts.
  8. Disable the unsupported plug-ins in the second instance (slapd-diopInstance), which you will use for enabling the DIOP plug-in.
    1. In Red Hat Console, locate and double-click the entry for the second instance of Directory Server.
      This opens the Directory Server Console for the second instance.
    2. Select the Configuration tab, and expand Plugins.
    3. Disable each of these plug-ins listed in Table 13.1, “Plug-in Status in DIOP-Enabled Directory Server”.
      To disable a plug-in, select the plug-in, and then, on the right panel, uncheck the Enable the Plugin option. Some plug-ins may depend on other plug-ins, and you may see messages that reflect such a dependency.
  9. Use the second instance to enable the DIOP feature, which is explained in the next section.

13.2. Enabling the DIOP Feature in Directory Server

For a Directory Server instance to support the DIOP feature, its default configuration needs to be modified - the server needs to be configured to use the null DN or the root suffix in the server. This can be done by adding the following entry to the dse.ldif file of the server instance in which you want to enable the DIOP feature:
dn: cn=,cn=mapping tree,cn=config objectClass: top objectClass: extensibleObject objectClass: nsMappingTree cn: nsslapd-state: container
You can modify the dse.ldif in either of the following ways:
  1. By editing the dse.ldif file directly:
    1. Shut down your Directory Server.
      service dirsrv stop
    2. In the text editor, open the dse.ldif file.
      The file is located in the /etc/dirsrv/slapd-instance_name directory.
    3. Add the above-mentioned entry, save your changes, and close the file.
    4. Restart the server.
      service dirsrv start
  2. By using the ldapmmodify command.
    1. You can also add the above entry by running the ldapmodify command on the slapd-<diopInstance> server with the LDIF input file containing the above entry. For example, your command might look like this:
      ./ldapmodify -h <host> -p <port> -W -D cn=directory manager -vcaf <ldif_file_containing_the_entry>
      Once you add the above entry to the server configuration, the DIOP functionality is enabled in the server.

Note

An example plug-in is shipped with the server to show how a DIOP pre-operation plug-in can be used to work with the DIOP-enabled server. For details about the sample plug-in, see Section 13.4, “Sample DIOP Plug-in”. To use the sample plug-in or your own custom plug-in in the server, see Section 13.3, “Using the DIOP Feature”.

13.3. Using the DIOP Feature

This section explains how you can verify whether the DIOP feature works in Directory Server. After you have successfully installed and configured two instances of Directory Servers, as explained in the preceding sections, follow the instructions in this section.
To help you understand the DIOP feature, a sample plug-in is provided. Details of this plug-in is covered in Section 13.3, “Using the DIOP Feature”. It is recommended that you review the sample plug-in first and use that as an example to develop your own plug-in.
To verify the DIOP feature, you may use the sample plug-in or reconfigure Directory Server to use your own plug-in. You can also remove the plug-in altogether from the server.
  1. If you want to use the sample plug-in, first build the plug-in, and then load it into the server:
    1. Shut down your DIOP-enabled Directory Server.
    2. Go to the directory in which the sample plug-in is located.
      cd install_directory//ldapserver/ldap/servers/slapd/
    3. Build the plug-in.
      gmake
    4. Modify the /etc/dirsrv/slapd-instance_name/dse.ldif file to include an entry for the plug-in. For instructions on to modify the dse.ldif file, refer to Section 13.3, “Using the DIOP Feature”. The entry shown below is for the sample plug-in.
      dn: cn=datainterop,cn=plugins,cn=config objectClass: top objectClass: nsSlapdPlugin 
      cn: datainterop nsslapd-pluginPath: install_directory//ldapserver/ldap/servers/slapd/libtest-plugin.so 
      nsslapd-pluginInitfunc: nullsuffix_init nsslapd-pluginType: preoperation nsslapd-pluginEnabled: on 
      nsslapd-pluginId: nullsuffix-preop nsslapd-pluginVersion: 7.1 nsslapd-pluginVendor: Red Hat, Inc. 
      nsslapd-pluginDescription: sample pre-operation null suffix plugin
    5. Restart the server to load the modified configuration.
  2. If you want to reconfigure the server to use your own plug-in:
    1. Shut down your DIOP-enabled Directory Server.
    2. Open the /etc/dirsrv/slapd-instance_name/dse.ldif file in a text editor.
    3. Modify the cn=datainterop,cn=plugins,cn=config entry, which holds the plug-in information, with data from your proprietary database plug-in.
    4. After you have done the required changes, restart the server to load the modified configuration.
  3. If you want to delete the sample plug-in from the server:
    1. Shut down your DIOP-enabled Directory Server.
    2. Open the /etc/dirsrv/slapd-instance_name/dse.ldif file in a text editor.
    3. Delete the cn=datainterop,cn=plugins,cn=config entry, which holds the plug-in information.
    4. Restart the server to load the modified configuration.
You can also use the ldapmodify command to make these changes.

13.4. Sample DIOP Plug-in

To help you understand the DIOP feature, a sample DIOP plug-in is included with Directory Server. This section provides an overview of the sample plug-in and explains how you can use the plug-in to verify whether the DIOP feature works in Directory Server. The preceding section, Section 13.3, “Using the DIOP Feature”, explains how you can use the sample plug-in. The next section, Section 13.4.1, “Debugging the Plug-in”, explains how to troubleshoot the plug-in.
The sample plug-in is located in the install_directory//ldapserver/ldap/servers/slapd/ directory. The shared library for the plug-in is named libtest-plugin.so and is implemented by
testdatainterop.c[.h]
testdbinterop.c 
db.h
located in the same directory.
Note the following:
  • The main goal of the sample plug-in is to show how to create a simple plug-in that supports data interoperability.
  • The plug-in does not attempt to create any usable functionality to access backends (database or files) but returns observable output uniformly to verify that the functions in the pre-operation plug-in have been accessed and executed for different LDAPoperations.
  • The plug-in demonstrates the use of APIs, which meet the requirements of the DIOP feature.
In the following table, the various required elements of the pre-operation plug-in are identified by the function calls used in the testdatainterop.c (to illustrate the use and simplify understanding).

Table 13.2. Elements of Pre-Operation Plug-in

Element Description
Description of the Plug-in
#define PLUGIN_NAME "nullsuffix-preop"
static Slapi_PluginDesc plugindesc =
 { PLUGIN_NAME, Red Hat, 7.1, sample pre-operation null suffix plugin }x
Initialization of the Plug-in by the Server
nullsuffix_init( Slapi_PBlock *pb )
In this function, all the callbacks are set up and will be called by the server for each LDAP operation.
Reserved Naming Contexts
(cn=schema, cn=config, cn=monitor)
slapi_op_reserved() is called to determine whether the operation should be handled internally by Directory Server; for example, whether the base on which the operation is applied is a reserved naming context. If returns a non-zero value, the plug-in does not attempt to handle that operation. This is performed by the following code snippet:
if( slapi_op_reserved(pb) ) {
	return PLUGIN_OPERATION_IGNORED;
}
Refer to testdatainterop.c for details.
The slapi_op_reserved() function, which can be used for reserving some of the naming contexts in the Directory Server (cn=schema,cn=config,cn=monitor), is called first in the database plug-in and then the call for turning off access control.
Sparse Tree Support Any modifications done to the server on the null suffix are processed by the plug-in. The plug-in writes the DN of all modifications received to a standalone BerkleyDB, and trying a simple test using LDIF entries without the required object classes or parent entries will still get processed by the server, populating the database created by the plug-in. See nullsuffix_modify and testdbinterop.c for details. The plug-in has not been coded for the retrieval of those entries but has been coded to demonstrate sparse tree support only.
Access Control Switching off access control for the operation is done by: slapi_operation_set_flag(op, SLAPI_OP_FLAG_NO_ACCESS_CHECK ); See testdatainterop.c for details.
Null Suffix Support The plug-in cannot control the support for null-suffix in the server. The support for null-suffix is done through configuration modification of the server as shown in Section 13.4, “Sample DIOP Plug-in”.
Building the Data Interoperability Plug-in The compiler used on Solaris is Forte. For example: cd install_directory//ldapserver/ldap/servers/slapd gmake libtest-plugin.so is generated.
Flag used for LDAP operation
Callback
SLAPI_PLUGIN_PRE_SEARCH_FN nullsuffix_search
SLAPI_PLUGIN_PRE_ADD_FN nullsuffix_add
SLAPI_PLUGIN_PRE_MODIFY_FN nullsuffix_modify
SLAPI_PLUGIN_PRE_DELETE_FN nullsuffix_delete
SLAPI_PLUGIN_PRE_BIND_FN nullsuffix_bind
SLAPI_PLUGIN_PRE_MODRDN_FN nullsuffix_modrdn

13.4.1. Debugging the Plug-in

If you need to debug the plug-in installed on a Solaris machine, you can use dbx:
  1. cd /usr/share/dirsrv/bin/slapd/server
  2. setenv NETSITE_ROOT /usr/share/dirsrv
  3. dbx ns-slapd
  4. run -d 65536 -D /usr/lib64/dirsrv/slapd-<diopInstance>
  5. Once the server starts up and error logs show that the server has started, press Ctrl + C.
  6. stop in user-defined-function-in-the-plugin
Similar steps can be done on other platforms, using the platform-specific debuggers and commands.

13.5. Plug-in API Reference

This section contains reference information on APIs that enable the following:

13.5.1. Preserving the Default Behavior of the Server

Directory Server implements internal backends for supporting subtrees cn=config, cn=schema, and cn=monitor, which are the reserved naming contexts for the server. For more information about these, check the Red Hat Directory Server Configuration, Command, and File Reference.
It may be required in some cases to let the default behavior of the server be preserved and not be intercepted by the custom pre-operation plug-ins. To implement a custom DIOP plug-in without affecting the default behavior of the Directory Server, a new function named slapi_op_reserved() is being made available. For details about this function, see Chapter 49, Functions Related to Data Interoperability.

13.5.2. Bypassing Access Control Checks

It may be desirable to disable access control checking for operations that are handled by the custom DIOP plug-in. To enable the plug-ins to bypass access control, a new flag, SLAPI_OP_FLAG_NO_ACCESS_CHECK, has been defined. You allow a custom plug-in to bypass access control by setting the flag on the operation-data structure, which is available to the plug-in through the parameter (pblock) setting; see Part V, “Parameter Block Reference”.
The following functions have been defined for this purpose:
For details about these functions, see Chapter 49, Functions Related to Data Interoperability.

Part III. Data Type and Structure Reference

Chapter 14. Data Type and Structure Reference

This part summarizes the data types and structures that you can use when writing Red Hat Directory Server plug-in functions.

14.1. berval

Represents binary data that is encoded using simplified Basic Encoding Rules (BER).
Syntax

This struct definition uses the following syntax:

typedef struct berval { 
 unsigned long bv_len; 
 char *bv_val; 
}BerValue;
Fields

This struct definition contains the following fields:

Table 14.1. Berval Field Listing

Field Description
bv_len The length of the data.
bv_val The binary data.
Description

The berval data structure represents binary data that is encoded using simplified Basic Encoding Rules (BER). The data and size of the data are included in a berval structure.

Use a berval structure when working with attributes that contain binary data (such as a JPEG or audio file).

14.2. computed_attr_context

Represents information used for a computed attribute.
Syntax

This struct definition uses the following syntax:

typedef struct _computed_attr_context computed_attr_context;
Description

computed_attr_context is the data type for an opaque structure that represents information about a computed attribute.

Before the Directory Server sends an entry back to a client, it determines if any of the attributes are computed, generates the attributes, and includes the generated attributes in the entry.
As part of this process, the server creates a computed_attr_context structure to pass relevant information to the functions generating the attribute values. Relevant information might include the attribute type, the BER-encoded request so far, and the parameter block.

14.3. LDAPControl

Represents a client or server control associated with an LDAP operation.
The LDAPControl data type represents a client or server control associated with an LDAP operation. Controls are part of the LDAPv3 protocol. You can use a client or server control to extend the functionality of an LDAP control.
For example, a server control can specify that the server must sort search results in an LDAP search operation.
Table 14.2, “Frontend API Functions for LDAP Controls” summarizes the frontend API functions that can be called to work with LDAP controls.

Table 14.2. Frontend API Functions for LDAP Controls

To perform this action... Call this function
Append a control to the end of an array or to a new array. slapi_add_control_ext()
Append an array of controls to the end of an array or to a new array. slapi_add_controls()
Create an LDAPControl structure based on a BerElement, an OID, and a criticality flag. It returns an LDAP error code.
slapi_build_control()
Create an LDAPControl structure based on a struct berval, an OID, and a criticality flag. It returns an LDAP error code.
slapi_build_control_from_berval()
Check for the presence of a specific LDAPControl. It returns non-zero for presence and zero for absence.
slapi_control_present()
Retrieve the LDAPMod contained in a Slapi_Mod structure. slapi_mod_get_ldapmod_passout()
Register the specified control with the server. This function associates the control with an object identification (OID). slapi_register_supported_control()
Retrieve an allocated array of object identifiers (OIDs) representing the controls supported by the Directory Server. slapi_get_supported_controls_copy()
Syntax

This struct definition uses the following syntax:

typedef struct ldapcontrol {
 char *ldctl_oid;
 struct berval ldctl_value;
 char ldctl_iscritical;
} LDAPControl;
Parameters

This function has the following parameters:

Table 14.3. LDAPControl Parameters

Field Description
ldctl_oid Object ID (OID) of the control.
ldctl_value berval structure containing the value used by the control for the operation.
ldctl_iscritical Specifies whether the control is critical to the operation. This field can have one of the following values:
  • LDAP_OPT_ON specifies that the control is critical to the operation.
  • LDAP_OPT_OFF specifies that the control is not critical to the operation.

14.4. LDAPMod

Specifies changes to an attribute in a directory entry.
LDAPMod is a type of structure that specifies changes to an attribute in a directory entry. Before you call the slapi_add_internal_pb() and slapi_modify_internal_pb() routines to add or modify an entry in the directory, you need to fill LDAPMod structures with the attribute values that you intend to add or change.
The following section of code sets up an LDAPMod structure to change the email address of a user's entry to bab@example.com:
Slapi_PBlock *rcpb;
LDAPMod attribute1;
LDAPMod *list_of_attrs[2];
char *mail_values[] = { "bab@example.com" , NULL };
Slapi_DN *dn;

...

/* Identify the entry that you want changed */

dn = "cn=Barbara Jensen, ou=Product Development, l=US, dc=example,dc=com" ;

/* Specify that you want to replace the value of an attribute */

attribute1.mod_op = LDAP_MOD_REPLACE;

/* Specify that you want to change the value of the mail attribute */

attribute1.mod_type = "mail" ;

/* Specify the new value of the mail attribute */

attribute1.mod_values = mail_values;

/* Add the change to the list of attributes that you want changed */


list_of_attrs[0] = &attribute_change ;
list_of_attrs[1] = NULL;

/* Update the entry with the change */

rcpb = slapi_modify_internal( dn, list_of_attrs, NULL, 1 );

...
Table 14.4, “Frontend API Functions for Entry Attribute Changes” summarizes the functions available to specify changes to an attribute in a directory entry.

Table 14.4. Frontend API Functions for Entry Attribute Changes

To perform this action... Call this function
Translate from entry to LDAPMod. slapi_entry2mods()
Dump the contents of an LDAPMod to the server log. slapi_mod_dump()
Get a reference to the LDAPMod in a Slapi_Mod structure. slapi_mod_get_ldapmod_byref()
Retrieve the reference to the LDAPMod contained in a Slapi_Mod structure. slapi_mod_get_ldapmod_passout()
Syntax

This struct definition uses the following syntax:

typedef struct ldapmod {
 int mod_op;
 char *mod_type;
 union mod_vals_u{
 char **modv_strvals;
 struct berval **modv_bvals;
 } mod_vals;

#define mod_values mod_vals.modv_strvals
#define mod_bvalues mod_vals.modv_bvals
} LDAPMod;
Fields

This struct definition contains the following fields:

Table 14.5. ldapmod Field Listing

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:
  • #define LDAP_MOD_ADD 0x00
    LDAP_MOD_ADD specifies to add the attribute values to the entry.
  • #define LDAP_MOD_DELETE 0x01
    LDAP_MOD_DELETE specifies to remove the attribute values from the entry.
  • #define LDAP_MOD_REPLACE 0x02
    LDAP_MOD_REPLACE specifies to replace the existing value of the attribute with the values in mod_values or mod_bvalues.
  • #define LDAP_MOD_BVALUES 0x80
In addition, if you are specifying binary values (as opposed to strings), you should OR (|) LDAP_MOD_BVALUES with the operation type. For example:
 mod->mod_op = LDAP_MOD_ADD | LDAP_MOD_BVALUES
mod_type Pointer to the attribute type that you want to add, delete, or replace.
mod_values_u A NULL-terminated array of string values for the attribute.
modv_strvals 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.
mod_vals Values that you want to add, delete, or replace.

14.5. mrFilterMatchFn

mrFilterMatchFn specifies the prototype for a filter_matching function that is called by the server when processing an extensible match filter.
An extensible match filter specifies either the OID of a matching rule or an attribute type (or both) that indicates how matching entries are found. For example, a sound-alike matching rule might find all entries that sound like a given value.
To handle an extensible match filter for a matching rule, you can write a matching rule plug-in.
You need to define the filter matching function, which is the function that has prototype specified by mrFilterMatchFn. The server calls this function for each potential matching candidate entry. The server passes pointers to a filter structure that you create in your filter factory function, the candidate entry, and the entry's attributes.
In your filter matching function, you can retrieve information about the filter, such as the attribute type and value specified in the filter, from the filter structure. You can then use this information to compare the value in the filter against the attribute values in the candidate entry.
Syntax

 

#include "slapi-plugin.h"
typedef int (*mrFilterMatchFn) (void* filter, Slapi_Entry* entry, Slapi_Attr* attrs);
Parameters

This function takes the following parameters:

Table 14.6. mrFilterMatchFn Parameter Listing

Parameter Description
filter Pointer to the filter structure created by your filter factory function. Refer to Section 11.4.3, “Writing a Filter Factory Function” for more information.
entry Pointer to the Slapi_Entry structure representing the candidate entry being checked by the server.
attrs Pointer to the Slapi_Attr structure representing the first attribute in the entry. To iterate through the rest of the attributes in the entry, call slapi_entry_next_attr().
Returns

This function returns an integer value of 0 if the filter is matched or -1 if the filter did not match. If an LDAP error occurs, it returns a value greater than 0.

14.6. plugin_referral_entry_callback

This typedef is used for LDAP referral entry callback functions, which are plugin-defined functions that process LDAP references generated by some internal searches.
Syntax

 

#include "slapi-plugin.h" 
typedef int (*plugin_referral_entry_callback) 
 (char *referral, void *callback_data);
Parameters

The function takes the following parameters:

Table 14.7. plugin_referral_entry_callback Parameter Listing

Parameter Description
referral The URL of a reference that is returned in response to an internal search call.
callback_data This value matches the callback_data pointer that was passed to the original internal operation function.
Returns

The following table lists this function's possible return values.

Table 14.8. plugin_referral_entry_callback Return Values

Return Value Description
0 Success
-1 An error occurred.
Description

A function that matches this typedef can be passed as the prec parameter of slapi_search_internal_callback_pb(), or as the ref_callback parameter of the slapi_seq_internal_callback_pb() function.

The LDAP referral entry callback function is called once for each referral entry found by a search operation, which means it could be called zero or any number of times.
The callback_data parameter can be used to pass arbitrary plug-in or operation-specific information to a referral entry callback function.

14.7. plugin_result_callback

This typedef is used for LDAP result callback functions, which are plugin-defined functions that process result messages that are generated by some internal search functions.
Syntax

This typedef uses the following syntax:

#include "slapi-plugin.h"
typedef void (*plugin_result_callback)(int rc, void *callback_data);
Parameters

This typedef takes the following parameters:

Table 14.9. plugin_result_callback Parameters

rc
The LDAP result code of the internal operation; for example, LDAP_SUCCESS.
callback_data This value matches the callback_data pointer that was passed to the original internal operation function.
Returns

The following table lists this function's possible return values.

Table 14.10. plugin_result_callback Return Values

Return Value Description
0 Success
-1 An error occurred.
Description

A function that matches this typedef can be passed as the prc parameter of slapi_search_internal_callback_pb() or as the res_callback parameter of slapi_seq_internal_callback_pb().

The LDAP result callback function should be called once for each search operation, unless the search is abandoned, in which case it will not be called.
The callback_data parameter can be used to pass arbitrary plug-in or operation-specific information to a result callback function.

14.8. plugin_search_entry_callback

This typedef is used for LDAP search entry callback functions, which are plug-in defined functions that process LDAP entries that are located by an internal search.
Syntax

This typedef uses the following syntax:

#include "slapi-plugin.h"
typedef int (*plugin_search_entry_callback)(Slapi_Entry *e, void *callback_data);
Parameters

This typedef takes the following parameters:

Table 14.11. plugin_search_entry_callback Parameters

e Pointer to the Slapi_Entry structure representing an entry found by the search.
callback_data This value matches the callback_data pointer that was passed to the original internal operation function.
Returns

The following table lists this function's possible return values.

Table 14.12. plugin_search_entry_callback Return Values

Return Value Description
0 Success
-1 An error occurred.
Description

A function that matches this typedef can be passed as the psec parameter of slapi_search_internal_callback_pb() or as the srch_callback parameter of slapi_seq_internal_callback_pb().

The LDAP referral entry callback function will be called once for each referral entry found by a search operation, which means it could be called zero or any number of times.
The callback_data parameter can be used to pass arbitrary plug-in or operation-specific information to a referral entry callback function.

14.9. send_ldap_referral_fn_ptr_t

send_ldap_referral_fn_ptr_t specifies the prototype for a callback function that you can write to send LDAPv3 referrals (search result references) back to the client. You can register your function so that it is called whenever the slapi_send_ldap_result() function is called.
Syntax

 

#include "slapi-plugin.h"
typedef int (*send_ldap_referral_fn_ptr_t)( Slapi_PBlock *pb, 
 Slapi_Entry *e, struct berval **refs, struct berval ***urls);
Parameters

This function takes the following parameters:

pb Parameter block.
e Pointer to the Slapi_Entry structure representing the entry with which you are working.
refs Pointer to the NULL-terminated array of berval structures containing the LDAPv3 referrals (search result references) found in the entry.
urls Pointer to the array of berval structures used to collect LDAP referrals for LDAPv2 clients.
Returns

This function returns 0 if successful, or -1 if an error occurs.

Description

The slapi_send_ldap_result() function is responsible for sending LDAPv3 referrals (search result references) back to the client. You can replace the function that sends LDAPv3 referrals to the client with your own function. To do this:

  1. Write a function with the prototype specified by send_ldap_result_fn_ptr_t.
  2. In your plug-in initialization function, register your function by setting the SLAPI_PLUGIN_PRE_REFERRAL_FN parameter in the parameter block to the name of your function if you are using the pre-operation plug-in. If you are using the post-operation plug-in, register your function by setting the SLAPI_PLUGIN_POST_REFERRAL_FN parameter in the parameter block to the name of your function.
See slapi_send_ldap_result() for information on the default function that sends LDAPv3 referrals to clients.

See Also

send_result()

14.10. send_ldap_result_fn_ptr_t

send_ldap_result_fn_ptr_t specifies the prototype for a callback function that you can write to send LDAP result codes back to the client. You can register your function so that it is called whenever the slapi_send_ldap_result() function is called.
Syntax

 

#include "slapi-plugin.h"
typedef void (*send_ldap_result_fn_ptr_t)( Slapi_PBlock *pb, 
 int err, char *matched, char *text, int nentries, struct berval **urls );
Parameters

The function has the following parameters:

pb Parameter block.
err LDAP result code that you want sent back to the client; for example, LDAP_SUCCESS.
matched When sending back an LDAP_NO_SUCH_OBJECT result code, use this argument to specify the portion of the target DN that could be matched.
text Error message that you want sent back to the client. Use NULL if you do not want an error message sent back.
nentries When sending back the result code for an LDAP search operation, use this argument to specify the number of matching entries found.
urls When sending back an LDAP_PARTIAL_RESULTS result code to an LDAPv2 client or an LDAP_REFERRAL result code to an LDAPv3 client, use this argument to specify the array of berval structures containing the referral URLs.

Description

The slapi_send_ldap_result() function is responsible for sending LDAP result codes back to the client. You can replace the function that sends LDAP result codes to the client with your own function. To do this:

  1. Write a function with the prototype specified by send_ldap_result_fn_ptr_t.
  2. In your plug-in initialization function, register your function for sending results to the client by setting the SLAPI_PLUGIN_PRE_RESULT_FN or SLAPI_PLUGIN_POST_RESULT_FN parameter, depending on the type of plug-in and if it is a pre-operation or post-operation, respectively, in the parameter block to the name of your function.

See Also

See slapi_send_ldap_result() for information on the default function that sends LDAP result codes to clients.

14.11. send_ldap_search_entry_fn_ptr_t

send_ldap_result_fn_ptr_t specifies the prototype for a callback function that you can write to send search results (entries found by a search) back to the client. You can register your function so that it is called whenever the slapi_send_ldap_search_entry() function is called.
Syntax

 

#include "slapi-plugin.h"
typedef int (*send_ldap_search_entry_fn_ptr_t)
 ( Slapi_PBlock *pb, Slapi_Entry *e, LDAPControl **ectrls, char **attrs, int attrsonly );
Description

The slapi_send_ldap_search_entry() function is responsible for sending entries found by a search back to the client. You can replace the function that sends entries to the client with your own function. To do this:

  1. Write a function with the prototype specified by send_ldap_search_entry_fn_ptr_t.
  2. In your plug-in initialization function, register your function by setting the SLAPI_PLUGIN_PRE_ENTRY_FN parameter in the parameter block to the name of your function if you are using the pre-operation plug-in. If you are using the post-operation plug-in, register your function by setting the SLAPI_PLUGIN_POST_ENTRY_FN parameter in the parameter block to the name of your function.

See Also

See slapi_send_ldap_search_entry() for information on the default function that sends entries to clients.

14.12. Slapi_Attr

Represents an attribute in an entry.
Syntax

 

#include "slapi-plugin.h" 
typedef struct slapi_attr Slapi_Attr;
Description

Slapi_Attr is the data type for an opaque structure that represents an attribute in a directory entry. In certain cases, your server plug-in may need to work with an entry's attributes. The following table summarizes the front-end API functions that you can call to work with attributes.

To ... ... Call this function
Add an attribute value. slapi_attr_add_value()
Return the base type of an attribute. slapi_attr_basetype()
Duplicate an attribute. slapi_attr_dup()
Get the first value of an attribute. slapi_attr_first_value()
Determine if certain flags are set. slapi_attr_flag_is_set()
Free an attribute. slapi_attr_free()
Put the values contained in an attribute into an array of berval structures. slapi_attr_get_bervals_copy()
Get the flags associated with an attribute. slapi_attr_get_flags()
Put the count of values of an attribute into an integer. slapi_attr_get_numvalues()
Search for an attribute type and give its OID string. slapi_attr_get_oid_copy()
Get the type of an attribute. slapi_attr_get_type()
Get the next value of an attribute. slapi_attr_get_valueset()
Determine the next value of an attribute. slapi_attr_next_value()
Initialize a valueset in a Slapi_Attr structure from a specified Slapi_ValueSet structure. slapi_attr_set_valueset()
Get information about the plug-in responsible for handling an attribute type. slapi_attr_type2plugin()
Compare two attribute names to determine if they represent the same attribute. slapi_attr_types_equivalent()
Find the first attribute in an entry. slapi_entry_first_attr()
Iterate through the attributes in an entry. slapi_entry_next_attr()
Determine if an attribute contains a given value. slapi_entry_attr_find()
Determine if an attribute has the specified value. slapi_attr_value_find()
Compare two attribute values. slapi_attr_value_cmp()
Add the changes in a modification to a valueset. slapi_valueset_set_from_smod()
Initialize a Slapi_ValueSet structure from another Slapi_ValueSet structure. slapi_valueset_set_valueset()

See Also

Slapi_Entry

14.13. Slapi_Backend

Represents a backend operation in the server plug-in-in.
Syntax

 

#include "slapi-plugin.h" 
typedef struct backend Slapi_Backend;
Description

Slapi_Backend is the data type for an opaque structure that represents a backend operation. The following table summarizes the front-end API functions that you can call to work with the backend operations.

To... ... Call this function
Add the specified suffix to the given backend and increment the backend's suffix count. slapi_be_addsuffix()
Set the flag to denote that the backend will be deleted on exiting. slapi_be_delete_onexit()
Check if the backend that contains the specified DN exists. slapi_be_exist()
Free memory and linked resources from the backend structure. slapi_be_free()
Get the instance information of the specified backend. slapi_be_get_instance_info()
Return the name of the specified backend. slapi_be_get_name()
Indicate if the database associated with the backend is in read-only mode. slapi_be_get_readonly()
Get pointer to a callback function that corresponds to the specified entry point into a given backend. slapi_be_getentrypoint()
Return the n+1 suffix associated with the specified backend. slapi_be_getsuffix()
Return the type of the backend. slapi_be_gettype()
Check if a flag is set in the backend configuration. slapi_be_is_flag_set()
Verify that the specified suffix matches a registered backend suffix. slapi_be_issuffix()
Indicate if the changes applied to the backend should be logged in the changelog. slapi_be_logchanges()
Create a new backend structure, allocate memory for it, and initialize values for relevant parameters. slapi_be_new()
Verify if the backend is private. slapi_be_private()
Find the backend that should be used to service the entry with the specified DN. slapi_be_select()
Find the backend that matches by the name of the backend. Backends can be identified by name and type. slapi_be_select_by_instance_name()
Set the specified flag in the backend. slapi_be_set_flag()
Set the instance information of the specified backend with given data. slapi_be_set_instance_info()
Set a flag to denote that the backend is meant to be read-only. slapi_be_set_readonly()
Set the entry point in the backend to the specified function. slapi_be_setentrypoint()
Return a pointer to the backend structure of the first backend. slapi_get_first_backend()
Return a pointer to the next backend, selected by index. slapi_get_next_backend()
Return the first root suffix of the DIT. slapi_get_first_suffix()
Return the DN of the next root suffix of the DIT. slapi_get_next_suffix()
Check if a suffix is a root suffix of the DIT. slapi_is_root_suffix()

14.14. slapi_backend_state_change_fnptr

slapi_backend_state_change_fnptr specifies the prototype for a callback function, which allows a plug-in to register for callback when a backend state changes.
Syntax

 

#include "slapi-plugin.h"
typedef void (*slapi_backend_state_change_fnptr)
 (void *handle, char *be_name, int old_be_state, int new_be_state);
Parameters

The function has the following parameters:

handle Pointer or reference to the address of the specified function.
be_name Name of the backend.
old_be_state Old backend state.
new_be_state New backend state.

Description

The function enables a plug-in to register for callback when the state of a backend changes. You may need to keep track of backend state changes when writing custom plug-ins.

14.15. Slapi_ComponentID

Represents the component ID in a directory entry.
Syntax

 

#include "slapi-plugin.h" 
typedef struct slapi_componentid Slapi_ComponentId;
Description

Slapi_ComponentID is the data type for an opaque structure that represents the component ID in a directory entry.

14.16. slapi_compute_callback_t

Represents a callback for evaluating computed attributes.
Syntax

 

#include "slapi-plugin.h"
typedef int (*slapi_compute_callback_t)
 (computed_attr_context *c, char* type, Slapi_Entry *e, slapi_compute_output_t outputfn);
Parameters

The function has the following parameters:

c Pointer to the computed_attr_context structure containing information relevant to the computed attribute.
type Attribute type of the attribute to be generated.
e Pointer to the Slapi_Entry structure representing the entry to be sent back to the client.
outputfn Pointer to the slapi_compute_output_t function responsible for BER-encoding the computed attribute and for adding it to the BER element to be sent to the client.

Returns

One of the following values:

  • -1 if the function is not responsible for generating the computed attribute.
  • 0 if the function successfully generates the computed attribute.
  • An LDAP error code if an error occurred.

Description

slapi_compute_callback_t specifies the prototype for a callback function that is called by the server when generating a computed attribute. If you want to use computed attributes, you should write a function of this type.

14.17. slapi_compute_output_t

Represents a prototype for an output function for contributed attributes.
Syntax

 

#include "slapi-plugin.h"
typedef int (*slapi_compute_output_t)
 (computed_attr_context *c, Slapi_Attr *a, Slapi_Entry *e);
Parameters

The function has the following parameters:

Returns

One of the following values:

  • 0 if the function successfully BER-encodes the computed attribute and adds it to the BER element to be sent to the client.
  • An LDAP error code if an error occurred.

Description

slapi_compute_output_t specifies the prototype for a callback function that BER-encodes a computed attribute and appends it to the BER element to be sent to the client. You do not need to define a function of this type. The server will pass a function of this type your slapi_compute_callback_t function. In your slapi_compute_callback_t function, you need to call this slapi_compute_output_t function.

For example:
static int my_compute_callback(computed_attr_context *c, char* type, 
	Slapi_Entry *e, slapi_compute_output_t outputfn)
	{
	...
	int rc; 
	Slapi_Attr my_computed_attr;
	...
	
	/* Call the output function after creating the computed 
	attribute and setting its values. */
	rc = (*outputfn) (c, &my_computed_attr, e);
	...
	}
In the example above, the slapi_compute_output_t function outputfn is passed in as an argument to my_compute_callback function. After generating the computed attribute, you need to call outputfn, passing it the context, the newly created attribute, and the entry. outputfn BER-encodes the attribute and appends it to the BER element to be sent to the client. You do not need to define outputfn yourself. You just need to call the function passed in as the last statement from the callback.

14.18. Slapi_Connection

Represents a connection.
Syntax

 

#include "slapi-plugin.h" 
typedef struct conn Slapi_Connection;
Description

Slapi_Connection is the data type for an opaque structure that represents a connection.

14.19. Slapi_CondVar

Represents a condition variable in a directory entry.
Syntax

 

#include "slapi-plugin.h" 
typedef struct slapi_condvar Slapi_CondVar;
Description

Slapi_CondVar is the data type for an opaque structure that represents a synchronization lock in the server plug-in. The following table summarizes the front-end API functions that you can call to modify synchronization locks in the server plug-in.

To ... ... Call this function
Destroy a condition variable. slapi_destroy_condvar()
Create a new condition variable. slapi_new_condvar()
Send notification about a condition variable. slapi_notify_condvar()
Wait for a condition variable. slapi_wait_condvar()

14.20. Slapi_Counter

Provides 64-bit integers with support for atomic operations, even on 32-bit systems. Slapi_Counter allows plug-ins to use global integers that can be updated by multiple worker threads in a thread-safe manner.
The Slapi_Counter structure is a wrapper around the actual counter value.
A mutex is used on platforms that do not provide 64-bit atomic operations.
Syntax

#include "slapi-plugin.h" 
typedef struct Slapi_Counter {
    PRUint64 value;
#ifndef ATOMIC_64BIT_OPERATIONS
    Slapi_Mutex *mutex;
#endif
} Slapi_Counter;

Associated Functions

Slapi_Counter defines settings for counters. The different functions available to Slapi_Counter structures are listed in Table 14.13, “Functions for Slapi_Counter”.

Table 14.13. Functions for Slapi_Counter

To ... ... Call this function
Create a new counter. slapi_counter_new()
Initialize a new counter. slapi_counter_init()
Increment the counter value and return the new value. slapi_counter_increment()
Decrement the counter and return the new value. slapi_counter_decrement()
Add a certain amount to the counter value. slapi_counter_add()
Subtract a certain amount from the counter value. slapi_counter_subtract()
Set the counter to a new, specified value and returns the updated value. slapi_counter_set_value()
Get the current value of the counter. slapi_counter_get_value()
Destroy an existing counter. slapi_counter_destroy()

14.21. Slapi_DN

Represents a distinguished name in a directory entry.
Syntax

 

#include "slapi-plugin.h" 
typedef struct slapi_dn Slapi_DN;
Description

Slapi_DN is the data type for an opaque structure that represents a distinguished name in the server plug-in. The following table summarizes the front-end API functions that you can call to work with distinguished names.

To ... ... Call this function
Supply authentication information from an LDAP bind operation. slapi_add_auth_response_control()
Specify a distinguished name is a root. slapi_dn_isroot()
Convert a DN to canonical format and all characters to lower case slapi_dn_normalize_case()
Normalize part of a DN value slapi_dn_normalize_to_end()
Build the new DN of an entry. slapi_moddn_get_newdn()
Add the RDN contained in a Slapi_RDN structure to the DN contained in a Slapi_DN structure. slapi_sdn_add_rdn()
Compare two DNs. slapi_sdn_compare()
Copy a DN. slapi_sdn_copy()
Clear a Slapi_DN structure. slapi_sdn_done()
Duplicate a Slapi_DN structure. slapi_sdn_dup()
Free a Slapi_DN structure. slapi_sdn_free()
Get the DN of the parent within a specific backend. slapi_sdn_get_backend_parent()
Get the DN from a Slapi_DN structure. slapi_sdn_get_dn()
Get the normalized DN of a Slapi_DN structure. slapi_sdn_get_ndn()
Get the length of the normalized DN of a Slapi_DN structure. slapi_sdn_get_ndn_len()
Get the parent DN of a given Slapi_DN structure. slapi_sdn_get_parent()
Get the RDN from a normalized DN. slapi_sdn_get_rdn()
Not implemented; do not use. Check if there is a RDN value that is a component of the DN structure. slapi_sdn_is_rdn_component()
Check if there is a DN value stored in a Slapi_DN structure. slapi_sdn_isempty()
Check if a DN is the parent of the parent of a DN. slapi_sdn_isgrandparent()
Check if a DN is the parent of a DN. slapi_sdn_isparent()
Check if a Slapi_DN structure contains a suffix of another. slapi_sdn_issuffix()
Allocate new Slapi_DN structure. slapi_sdn_new()
Create a new Slapi_DN structure. slapi_sdn_new_dn_byref()
Create a new Slapi_DN structure. slapi_sdn_new_dn_byval()
Create a new Slapi_DN structure. slapi_sdn_new_dn_passin()
Create a new Slapi_DN structure. slapi_sdn_new_ndn_byref()
Create a new Slapi_DN structure. slapi_sdn_new_ndn_byval()
Check if an entry is in the scope of a certain base DN. slapi_sdn_scope_test()
Set a DN value in a Slapi_DN structure. slapi_sdn_set_dn_byref()
Set a DN value in a Slapi_DN structure. slapi_sdn_set_dn_byval()
Set a DN value in a Slapi_DN structure. slapi_sdn_set_dn_passin()
Set a normalized DN in a Slapi_DN structure. slapi_sdn_set_ndn_byref()
Set a normalized DN in a Slapi_DN structure. slapi_sdn_set_ndn_byval()
Set a new parent in an entry. slapi_sdn_set_parent()
Set a new RDN for an entry. slapi_sdn_set_rdn()
Convert the second RDN type value to the berval value. slapi_rdn2typeval()

See Also

Slapi_PBlock

14.22. Slapi_Entry

Represents an entry in the directory.
Syntax

 

#include "slapi-plugin.h" 
typedef struct slapi_entry Slapi_Entry;
Description

Slapi_Entry is the data type for an opaque structure that represents an entry in the directory. In certain cases, your server plug-in may need to work with an entry in the directory. The following table summarizes the front-end API functions that you can call to work with entries.

To ... ... Call this function
Generate an LDIF string description. slapi_entry2str()
Generate an LDIF string descriptions with options. slapi_entry2str_with_options()
Add components in an entry's RDN. slapi_entry_add_rdn_values()
Add a string value to an attribute in an entry. slapi_entry_add_string()
Add a data value to an attribute in an entry. slapi_entry_add_value()
Add an array of data values to an attribute in an entry. slapi_entry_add_values_sv()
Add a data value to an attribute in an entry. slapi_entry_add_valueset()
Allocate memory for an entry structure. slapi_entry_alloc()
Applies an array of LDAPMod to a Slapi_Entry. Section 24.9, “slapi_entry_apply_mods()”
Delete an attribute from an entry. slapi_entry_attr_delete()
Check if an entry contains a specific attribute. slapi_entry_attr_find()
Get the first value as a string. slapi_entry_attr_get_charptr()
Get the values of a multi-valued attribute of an entry. slapi_entry_attr_get_charray()
Get the first value as an integer. slapi_entry_attr_get_int()
Get the first value as a long. slapi_entry_attr_get_long()
Get the first value as an unsigned integer. slapi_entry_attr_get_uint()
Get the first value as an unsigned long. slapi_entry_attr_get_ulong()
Check if an attribute in an entry contains a value. slapi_entry_attr_has_syntax_value()
Add an array to the attribute values in an entry. slapi_entry_attr_merge_sv()
Replace the values of an attribute with a string. slapi_entry_attr_replace_sv()
Set the first value as a string. slapi_entry_attr_set_charptr()
Set the first value as an integer. slapi_entry_attr_set_int()
Set the first value as a long. slapi_entry_attr_set_long()
Set the first value as an unsigned integer. slapi_entry_attr_set_uint()
Set the first value as an unsigned long. slapi_entry_attr_set_ulong()
Delete a string from an attribute. slapi_entry_delete_string()
Remove a Slapi_Value array from an attribute. slapi_entry_delete_values_sv()
Copy an entry, its DN, and its attributes. slapi_entry_dup()
Find the first attribute in an entry. slapi_entry_first_attr()
Free an entry from memory. slapi_entry_free()
Get the DN from an entry. slapi_entry_get_dn()
Return the DN of an entry as a constant. slapi_entry_get_dn_const()
Return the normalized distinguished name (NDN) of an entry. slapi_entry_get_ndn()
Return the Slapi_DN from an entry. slapi_entry_get_sdn()
Return a Slapi_DN from an entry as a constant. slapi_entry_get_sdn_const()
Get the unique ID from an entry. slapi_entry_get_uniqueid()
Determine if the specified entry has child entries. slapi_entry_has_children()
Initialize the values of an entry. slapi_entry_init()
Add an array of data values to an attribute in an entry. slapi_entry_merge_values_sv()
Find the next attribute in an entry. slapi_entry_next_attr()
Check if values present in an entry's RDN are also present as attribute values. slapi_entry_rdn_values_present()
Determine if an entry complies with the schema for its object class. slapi_entry_schema_check()
Set the DN of an entry. slapi_entry_set_dn()
Set the Slapi_DN value in an entry. slapi_entry_set_sdn()
Set the unique ID in an entry. slapi_entry_set_uniqueid()
Return the size of an entry. slapi_entry_size()
Determine if an entry is the root DSE. slapi_is_rootdse()
Convert an LDIF description into an entry. slapi_str2entry()

See Also

Slapi_Attr

14.23. Slapi_Filter

Represents a search filter.
Syntax

 

#include "slapi-plugin.h" 
typedef struct slapi_filter Slapi_Filter;
Description

Slapi_Filter is the data type for an opaque structure that represents an search filter. (For more information on search filters, see Section 5.5, “Working with Entries, Attributes, and Values”.) The following table summarizes the front-end API functions that you can call to work with filters.

To ... ... Call this function
Determine if an entry matches a filter's criteria. slapi_filter_test()
Get the filter type. slapi_filter_get_choice()
Get the attribute type and value used for comparison in a filter (only applicable to LDAP_FILTER_EQUALITY, LDAP_FILTER_GE, LDAP_FILTER_LE, and LDAP_FILTER_APPROX searches). slapi_filter_get_ava()
Get the type of attribute that the filter is searching for (only applicable to LDAP_FILTER_PRESENT searches). slapi_filter_get_type()
Get the substring pattern used for the filter (applicable only to LDAP_FILTER_SUBSTRING searches). slapi_filter_get_subfilt()
Convert a string representation of a filter to a filter of the data type Slapi_Filter. slapi_str2filter()
Construct a new LDAP_FILTER_AND, LDAP_FILTER_OR, or LDAP_FILTER_NOT filter from other filters. slapi_filter_join()
Get the components of a filter (only applicable to LDAP_FILTER_AND, LDAP_FILTER_OR, and LDAP_FILTER_NOT searches). slapi_filter_list_first()
Free a filter from memory. slapi_filter_free()

14.24. Slapi_MatchingRuleEntry

Slapi_MatchingRuleEntry is the data type for an opaque structure that represents a matching rule.
The matching rule definition can be specified as a dynamic declaration using functions such as slapi_matchingrule_new() or slapi_matchingrule_set().
Alternatively, the matching rule definition can also be specified as a static declaration. For example:
static Slapi_MatchingRuleEntry
integerMatch = { INTEGERMATCH_OID, NULL /* no alias? */,
	"integerMatch", "The rule evaluates to TRUE if and only if the
attribute value and the assertion value are the same integer value.",
	INTEGER_SYNTAX_OID, 0 /* not obsolete */ };
...
int
int_init( Slapi_PBlock *pb )
{
	int rc;
...
	rc = slapi_matchingrule_register(&integerMatch);
...
}
Table 14.14, “Frontend API Functions for Slapi_MatchingRuleEntry” summarizes the front-end API functions that can be called to work with matching rules.
Syntax

This function has the following syntax:

typedef struct slapi_matchingRuleEntry {
	char *mr_oid;
	char *mr_oidalias;
	char *mr_name;
	char *mr_desc;
	char *mr_syntax;
	int mr_obsolete;
} slapi_MatchingRuleEntry;
typedef struct slapi_matchingRuleEntry Slapi_MatchingRuleEntry;
See Also

 

Table 14.14. Frontend API Functions for Slapi_MatchingRuleEntry

To perform this action... Call this function
Compare two berval structures to determine if they are equal. slapi_berval_cmp()
Call the indexer function associated with an extensible match filter. slapi_mr_filter_index()
Free the specified matching rule structure (and optionally, its members) from memory. slapi_matchingrule_free()
Get information about a matching rule. slapi_matchingrule_get()
Call the indexer factory function for the plug-in responsible for a specified matching rule. slapi_mr_indexer_create()
Allocate memory for a new Slapi_MatchingRuleEntry structure. slapi_matchingrule_new()
Register the specified matching rule with the server. slapi_matchingrule_register()
Set information about the matching rule. slapi_matchingrule_set()
Determines if a matching rule is a valid ordering matching rule for the given syntax. slapi_matchingrule_is_ordering()
Reserved for future use. slapi_matchingrule_unregister()

14.25. Slapi_Mod

Represents a single LDAP modification to a directory entry.
Syntax

 

#include "slapi-plugin.h" 
typedef struct slapi_mod Slapi_Mod;
Description

Slapi_Mod is the data type for an opaque structure that represents LDAPMod modifications to an attribute in a directory entry.

The following table summarizes the front-end API functions that you can call to manipulate directory entries.
To ... ... Call this function
Add a value to a Slapi_Mod structure. slapi_mod_add_value()
Free internals of Slapi_Mod structure. slapi_mod_done()
Dump the contents of an LDAPMod to the server log. slapi_mod_dump()
Free a Slapi_Mod structure. slapi_mod_free()
Initialize a Slapi_Mod iterator and return the first attribute value. slapi_mod_get_first_value()
Get a reference to the LDAPMod in a Slapi_Mod structure. slapi_mod_get_ldapmod_byref()
Retrieve the LDAPMod contained in a Slapi_Mod structure. slapi_mod_get_ldapmod_passout()
Increment the Slapi_Mod iterator and return the next attribute value. slapi_mod_get_next_value()
Get the number of values in a Slapi_Mod structure. slapi_mod_get_num_values()
Get the operation type of Slapi_Mod structure. slapi_mod_get_operation()
Get the attribute type of a Slapi_Mod structure. slapi_mod_get_type()
Initialize a Slapi_Mod structure. slapi_mod_init()
Initialize a Slapi_Mod structure that is a wrapper for an existing LDAPMod. slapi_mod_init_byref()
Initialize a modification by value. slapi_mod_init_byval()
Initialize a Slapi_Mod from an LDAPMod. slapi_mod_init_passin()
Initializes the given smod with the given LDAP operation and attribute type. slapi_mod_init_valueset_byval()
Determine whether a Slapi_Mod structure is valid. slapi_mod_isvalid()
Allocate a new Slapi_Mod structure. slapi_mod_new()
Remove the value at the current Slapi_Mod iterator position. slapi_mod_remove_value()
Set the operation type of a Slapi_Mod structure. slapi_mod_set_operation()
Set the attribute type of a Slapi_Mod. slapi_mod_set_type()
See Also

LDAPMod

14.26. Slapi_Mods

Represents two or more LDAP modifications to a directory entry
Syntax

 

#include "slapi-plugin.h" 
typedef struct slapi_mods Slapi_Mods;
Description

Slapi_Mods is the data type for an opaque structure that represents LDAPMod manipulations that can be made to a directory entry.

The following table summarizes the front-end API functions that you can call to manipulate directory entries.
To ... ... Call this function
Create a Slapi_Entry from an array of LDAPMod. slapi_mods2entry()
Append a new mod with a single attribute value to Slapi_Mods structure. slapi_mods_add()
Append an LDAPMod to a Slapi_Mods structure. slapi_mods_add_ldapmod()
Append a new mod to a Slapi_Mods structure, with attribute values provided as an array of berval. slapi_mods_add_modbvps()
Append a new mod to a Slapi_Mods structure, with attribute values provided as an array of Slapi_Value. slapi_mods_add_mod_values()
Append a new mod to Slapi_Mods structure with a single attribute value provided as a string. slapi_mods_add_string()
Complete a modification. slapi_mods_done()
Dump the contents of a Slapi_Mods structure to the server log. slapi_mods_dump()
Free a Slapi_Mods structure. slapi_mods_free()
Initialize a Slapi_Mods iterator and return the first LDAPMod. slapi_mods_get_first_mod()
Get a reference to the array of LDAPMod in a Slapi_Mods structure. slapi_mods_get_ldapmods_byref()
Retrieve the array of LDAPMod contained in a Slapi_Mods structure. slapi_mods_get_ldapmods_passout()
Increment the Slapi_Mods iterator and return the next LDAPMod. slapi_mods_get_next_mod()
Increment the Slapi_Mods iterator and return the next mod wrapped in a Slapi_Mods. slapi_mods_get_next_smod()
Get the number of mods in a Slapi_Mods structure. slapi_mods_get_num_mods()
Initialize a Slapi_Mods. slapi_mods_init()
Initialize a Slapi_Mods that is a wrapper for an existing array of LDAPMod. slapi_mods_init_byref()
Initialize a Slapi_Mods structure from an array of LDAPMod. slapi_mods_init_passin()
Insert an LDAPMod into a Slapi_Mods structure after the current iterator position. slapi_mods_insert_after()
Insert an LDAPMod anywhere in a Slapi_Mods. slapi_mods_insert_at()
Insert an LDAPMod into a Slapi_Mods structure before the current iterator position. slapi_mods_insert_before()
Decrement the Slapi_Mods current iterator position. slapi_mods_iterator_backone()
Allocate a new uninitialized Slapi_Mods structure. slapi_mods_new()
Remove the mod at the current Slapi_Mods iterator position. slapi_mods_remove()
See Also

LDAPMod and Slapi_Mod

14.27. Slapi_Mutex

Represents a mutually exclusive lock in the server plug-in.
Syntax

 

#include "slapi-plugin.h" 
typedef struct slapi_mutex Slapi_Mutex;
Description

Slapi_Mutex is the data type for an opaque structure that represents a mutual exclusive lock (mutex) in the server plug-in.

The following table summarizes the front-end API functions that you can call to work with mutually exclusive locks.
To ... ... Call this function
Destroy a mutex. slapi_destroy_mutex()
Lock a mutex. slapi_lock_mutex()
Create a new mutex. slapi_new_mutex()
Unlock a mutes. slapi_unlock_mutex()

14.28. Slapi_Operation

Represents an operation pending from an LDAP client.
Syntax

 

#include "slapi-plugin.h" 
typedef struct op Slapi_Operation;
Description

Slapi_Operation is the data type for an opaque structure that represents an operation pending from an LDAP client.

The following table summarizes the front-end API functions that you can call to work with mutually exclusive locks.
To ... ... Call this function
Determine if the client has abandoned the current operation. slapi_op_abandoned()
Get the type of a Slapi_Operation. slapi_op_get_type()

14.29. Slapi_PBlock

Contains name-value pairs, known as parameter blocks, that you can get or set for each LDAP operation.
Syntax

 

#include "slapi-plugin.h" 
typedef struct slapi_pblock Slapi_PBlock;
Description

Slapi_PBlock contains name-value pairs that you can use to retrieve information from the server and set information to be used by the server.

For most types of plug-in functions, the server passes in a Slapi_PBlock structure that typically includes data relevant to the operation being processed. You can get the value of a parameter by calling the slapi_pblock_get() function.
For example, when the plug-in function for an LDAP bind operation is called, the server puts the DN and credentials in the SLAPI_BIND_TARGET and SLAPI_BIND_CREDENTIALS parameters of the Slapi_PBlock structure. You can call slapi_pblock_get() to get the DN and credentials of the client requesting authentication.
For plug-in initialization functions, you can use the Slapi_PBlock structure to pass information to the server, such as the description of your plug-in and the names of your plug-in functions. You can set the value of a parameter by calling the slapi_pblock_set() function.
For example, in order to register a pre-operation bind plug-in function, you need to call slapi_pblock_set() to set the version number, description, and name of the plug-in function as the SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_DESCRIPTION, and SLAPI_PLUGIN_PRE_BIND_FN parameters.
The available parameters that you can use depends on the type of plug-in function you are writing.
The following table summarizes the front-end API functions that you can call to work with block parameters.
To ... ... Call this function
Set up a parameter block so that it can be used by slapi_add_internal_pb() for an internal add operation. slapi_add_entry_internal_set_pb()
Add an LDAP add operation based on a parameter block to add a new directory entry. slapi_add_internal_pb()
Set up a parameter block so that it can be used by slapi_add_internal_pb() for an internal add operation; the entry is constructed from a DN and a set of attributes. slapi_add_internal_set_pb()
Perform an LDAP delete operation based on a parameter block to remove a directory entry. slapi_delete_internal_pb()
Delete an internal parameter block set. slapi_delete_internal_set_pb()
Perform an LDAP modify operation based on a parameter block to modify a directory entry. slapi_modify_internal_pb()
Set up a parameter block so that it can be used by slapi_modify_internal_pb() for an internal modify operation. slapi_modify_internal_set_pb()
Perform an LDAP modify RDN operation based on a parameter block to rename a directory entry. slapi_modrdn_internal_pb()
Free a pblock from memory. slapi_pblock_destroy()
Get the value from a pblock. slapi_pblock_get()
Initialize an existing parameter block so that it can be reused. Section 35.3, “slapi_pblock_init()”
Create a new pblock. slapi_pblock_new()
Set the value of a pblock. slapi_pblock_set()
Set up a parameter block so that it can be used by slapi_modrdn_internal_pb() for an internal rename operation. slapi_rename_internal_set_pb()
Perform an LDAP search operation based on a parameter block to search the directory. slapi_search_internal_callback_pb()
Search for an internal parameter block. slapi_search_internal_pb()
Set up a parameter block so that it can be used by slapi_search_internal_pb() for an internal search operation. slapi_search_internal_set_pb()
Perform an internal sequential access operation. slapi_seq_internal_callback_pb()
Set up a parameter block for use by slapi_seq_internal_callback_pb() for an internal, sequential-access operation. slapi_seq_internal_set_pb()

14.30. Slapi_PluginDesc

Represents information about a server plug-in.
Syntax

 

typedef struct slapi_plugindesc {
 char *spd_id;
 char *spd_vendor;
 char *spd_version;
 char *spd_description;
} Slapi_PluginDesc;
Parameters

The function has the following parameters:

spd_id Unique identifier for the server plug-in.
spd_vendor Name of the vendor supplying the server plug-in; for example, example.com.
spd_version Version of the server plug-in used for your own tracking purposes; for example, 0.5. This is different from the value of the SLAPI_PLUGIN_VERSION, which specifies the general version of plug-in technology; the Directory Server uses that version to determine if it supports a plug-in.
spd_description Description of the server plug-in.
Description

Slapi_PluginDesc represents information about a server plug-in. In your initialization function, you specify information about your plug-in in this structure and call slapi_pblock_set() to put the structure in the SLAPI_PLUGIN_DESCRIPTION parameter.

See Also

For more information on using Slapi_PluginDesc to specify plug-in information, see Section 2.2.2, “Specifying Information about the Plug-in”.

14.31. Slapi_RDN

Represents a relative distinguished name in a directory entry.
Syntax

 

#include "slapi-plugin.h" 
typedef struct slapi_rdn Slapi_RDN;
Description

Slapi_RDN is the data type for an opaque structure that represents a relative distinguished name in the server plug-in.

The following table summarizes the front-end API functions that you can call to work with relative distinguished names.
To ... ... Call this function
Add a new RDN to an existing RDN structure. slapi_rdn_add()
Compare two RDNs. slapi_rdn_compare()
Check if a Slapi_RDN structure holds any RDN matching a given type/value pair. slapi_rdn_contains()
Check if a Slapi_RDN structure contains any RDN matching a given type. slapi_rdn_contains_attr()
Clear a Slapi_RDN structure. slapi_rdn_done()
Free a Slapi_RDN structure. slapi_rdn_free()
Get the type/value pair of the first RDN. slapi_rdn_get_first()
Get the index of the RDN. slapi_rdn_get_index()
Get the position and the attribute value of the first RDN.  
Get the RDN type/value pair from the RDN. slapi_rdn_get_next()
Get the number of RDN type/value pairs. slapi_seq_internal_set_pb()
Get the RDN from a Slapi_RDN structure. slapi_seq_internal_set_pb()
Initialize a Slapi_RDN structure. slapi_rdn_init()
Initialize a Slapi_RDN structure with an RDN value taken from a given DN. slapi_rdn_init_dn()
Initializes Slapi_RDN structure with an RDN value. slapi_rdn_init_rdn()
Initialize a Slapi_RDN structure with an RDN value taken from the DN contained in a given Slapi_RDN.  
Check if an RDN value is stored in a Slapi_RDN structure. slapi_rdn_isempty()
Allocate a new Slapi_RDN structure. slapi_rdn_new()
Create a new Slapi_RDN structure. slapi_rdn_new_dn()
Create a new Slapi_RDN structure and set an RDN value. slapi_rdn_new_rdn()
Create a new Slapi_RDN structure and set an RDN value taken from the DN contained in a given Slapi_RDN structure. slapi_rdn_new_sdn()
Remove an RDN type/value pair. slapi_rdn_remove()
Remove an RDN type/value pair from a Slapi_RDN. slapi_rdn_remove_attr()
Remove an RDN type/value pair from a Slapi_RDN structure. slapi_rdn_remove_index()
Set an RDN value in a Slapi_RDN structure. slapi_rdn_set_dn()
Set an RDN in a Slapi_RDN structure. slapi_rdn_set_rdn()
Set an RDN value in a Slapi_RDN structure. slapi_rdn_set_sdn()
Add an RDN to a DN.  

14.32. Slapi_Task

An opaque structure that represents a task that has been initiated.
Common Directory Server tasks, including importing, exporting, and indexing databases, can be initiated through a special task configuration entry in cn=tasks,cn=config. These task operations are managed using the Slapi_Task structure.
Syntax

 

#include "slapi-plugin.h" 
typedef struct slapi_task Slapi_Task;
Associated typedefs

There are two additional typedef declarations associated with the Slapi_Task structure.

Table 14.15. typedefs for the Slapi_Task Structure

typedef Description
dseCallbackFn Sets callback information for the frontend plug-in.
TaskCallbackFn Defines a callback used by Slapi_Task cancel and destructor functions.
Associated Functions

All of the available functions for Directory Server tasks are listed in Table 14.16, “Functions for the Slapi_Task Structure”.

Table 14.16. Functions for the Slapi_Task Structure

To ... ... Call this function
Create a new server task and returns a poinrter to the Slapi_Task structure. slapi_new_task()
Update a task entry to indicate that the task is running. slapi_task_begin()
Cancel a current task. slapi_task_cancel()
Decrement the task reference count. slapi_task_dec_refcount()
Write that the task is complete and returns the result code. slapi_task_finish()
Retrieve an opaque data pointer from the task. slapi_task_get_data()
Check the current reference count of the task. If a task has multiple threads, this shows whether the individual tasks have completed. slapi_task_get_refcount()
Show the current state of the task. slapi_task_get_state()
Automatically increment the task progress, which updates the task entry. slapi_task_inc_progress()
Increment the task reference count, if the task uses multiple threads. slapi_task_inc_refcount()
Write changes to a log attribute for the task entry. slapi_task_log_notice()
Update the task status attribute in the entry to maintain a running display of the task status. slapi_task_log_status()
Register a task handler function. slapi_task_register_handler()
Set a callback to be used when a task is cancelled. slapi_task_set_cancel_fn()
Append an opaque object pointer to the task process. slapi_task_set_data()
Set a callback to be used when a task is destroyed. slapi_task_set_destructor_fn()
Contain the task's status. slapi_task_status_changed()

14.32.1. dseCallbackFn

Sets callback information for the frontend plug-in.
Syntax

 

#include "slapi-plugin.h"
typedef int (*dseCallbackFn)(Slapi_PBlock *, Slapi_Entry *, Slapi_Entry *,
                            int *, char*, void *);
Returns

This callback must return one of the following messages:

  • SLAPI_DSE_CALLBACK_OK (0) for successful operations, meaning that any directory changes can be performed.
  • SLAPI_DSE_CALLBACK_ERROR (1) for any errors, which means that any directory changes cannot be performed.
  • SLAPI_DSE_CALLBACK_DO_NOT_APPLY (-1), which is returned if there are no errors but the changes should still not be applied. This only applies for modify operations; otherwise, the server itnerprets SLAPI_DSE_CALLBACK_DO_NOT_APPLY as SLAPI_DSE_CALLBACK_ERROR.

14.32.2. TaskCallbackFn

Defines a callback used specifically by Slapi_Task structure cancel and destructor functions.
Syntax

 

#include "slapi-plugin.h"
typedef void (*TaskCallbackFn)(Slapi_Task *task);
Parameters

This function takes the following parameter:

Parameter Description
task Points to the task operation which is being performed by the server.
Returns

Currently, this callback only returns a success message (0). The actual return values for the functions are not checked by the callback.

14.33. Slapi_UniqueID

Represents the unique identifier of a directory entry.
Syntax

 

#include "slapi-plugin.h" 
typedef struct _guid_t Slapi_UniqueID;
Description

Slapi_UniqueID is the data type for an opaque structure that represents the unique identifier of a directory entry. All directory entries contain a unique identifier. Unlike the distinguished name (DN), the unique identifier of an entry never changes, providing a good way to refer unambiguously to an entry in a distributed/replicated environment.

14.34. Slapi_Value

Represents the value of the attribute in a directory entry.
Syntax

 

#include "slapi-plugin.h" 
typedef struct slapi_value Slapi_Value;
Description

Slapi_Value is the data type for an opaque structure that represents the value of an attribute in a directory entry.

The following table summarizes the front-end API functions that you can call to work with directory entry values.
To ... ... Call this function
Compare a value. slapi_value_compare()
Duplicate a value.  
Free a Slapi_Value structure from memory. slapi_value_free()
Get the berval structure of the value. slapi_value_get_berval()
Get flags from a Slapi_Value structure. slapi_value_get_flags()
Convert the value of an integer. slapi_value_get_int()
Get the length of a value. slapi_value_get_length()
Get the actual length of the value. slapi_value_get_long()
Convert a value into a long integer. slapi_value_get_long()
Return the value as a string. The value returned may not be null-terminated. slapi_value_get_string()
Convert the value into an unsigned integer. slapi_value_get_uint()
Convert the value into an unsigned long. slapi_value_get_ulong()
Initialize a Slapi_Value structure with no values. slapi_value_init()
Initialize a Slapi_Value structure from the berval structure. slapi_value_init_berval()
Initialize a Slapi_Value structure from a string. slapi_value_init_string()
Initialize a Slapi_Value structure with a value contained in a string. slapi_value_init_string_passin()
Allocate a new Slapi_Value structure. slapi_value_new()
Allocate a new Slapi_Value structure from a berval structure. slapi_value_new_berval()
Allocate a new Slapi_Value structure from a string. slapi_value_new_string()
Allocate a new Slapi_Value structure and initializes it from a string. slapi_value_new_string_passin()
Allocate a new Slapi_Value from another Slapi_Value structure. slapi_value_new_value()
Set the value. slapi_value_set()
Copy the value from a berval structure into a Slapi_Value structure. slapi_value_get_berval()
Set flags for a Slapi_Value structure. slapi_value_set_flags()
Set the integer value of a Slapi_Value structure. slapi_value_set_int()
Copy a string into thevalue. slapi_value_set_string()
Set the value. slapi_value_set_string_passin()
Copy the value of a Slapi_Value structure into another Slapi_Value structure. slapi_value_set_value()
Set flags to the array of a Slapi_Value structure. slapi_values_set_flags()
See Also

Slapi_ValueSet

14.35. Slapi_ValueSet

Represents a set of Slapi_Value (or a list of Slapi_Value).
Slapi_ValueSet is the data type for an opaque structure that represents set of Slapi_Value (or a list of Slapi_Value).
Syntax

 

#include "slapi-plugin.h" 
typedef struct slapi_value_set Slapi_ValueSet;
The following table summarizes the front-end API functions that you can call to work with sets of Slapi_Value.
To ... ... Call this function
Add a Slapi_Value in the Slapi_ValueSet structure. slapi_valueset_add_value()
Count the values in a valueset. slapi_valueset_count()
Free the values contained in the Slapi_ValueSet structure. slapi_valueset_done()
Find the value in a valueset using the syntax of an attribute. slapi_valueset_find()
Get the first value of a Slapi_ValueSet structure. slapi_valueset_first_value()
Free the specified Slapi_ValueSet structure and its members from memory. slapi_valueset_free()
Reset a Slapi_ValueSet structure to no values. slapi_valueset_init()
Allocate a new Slapi_ValueSet structure. slapi_valueset_next_value()
Get the next value from a Slapi_ValueSet structure.  
Add the changes in a modification to a valueset. slapi_valueset_set_from_smod()
Initialize a Slapi_ValueSet structure from another Slapi_ValueSet structure. slapi_valueset_set_valueset()

14.36. Replication Session Hooks Callbacks

These typedef declarations are used to define replication session hooks for Directory Server and its clients, including applications like Red Hat Enterprise IPA.

Table 14.17. Replication Session Hooks Types

typedef Description
repl_session_plugin_agmt_init_cb Used to initialize the replication agreement to begin replication.
repl_session_plugin_pre_acquire_cb Defines the data about the initiating master server to send to the replica.
repl_session_plugin_reply_acquire_cb Defines the information about the replica to send to the master.
repl_session_plugin_post_acquire_cb Posts the response from the replica to the master server.
repl_session_plugin_recv_acquire_cb Receives the data from the replica.
repl_session_plugin_destroy_agmt_cb Destroys a replication agreement when the operation is complete.

14.36.1. repl_session_plugin_agmt_init_cb

Initializes a replication agreement.
Syntax

 

typedef void * (*repl_session_plugin_agmt_init_cb)(const Slapi_DN *repl_subtree);
Parameters

This function takes the following parameters:

Parameter Description
repl_subtree Gives the subtree that is involved in replication.

14.36.2. repl_session_plugin_pre_acquire_cb

Defines the data about the initiating master server to send to the replica.
Syntax

 

typedef int (*repl_session_plugin_pre_acquire_cb)(void *cookie, const Slapi_DN *repl_subtree,
                                          int is_total, char **data_guid, struct berval **data);
Parameters

This function takes the following parameters:

Parameter Description
cookie Private data used by the plug-in. This is the value returned by the replication plug-in init function (if any) and passed to all plug-in functions.
repl_subtree Gives the subtree that is involved in replication.
data_guid Sends an identifier for the expected data.
data_guid Contains the data.

14.36.3. repl_session_plugin_reply_acquire_cb

Defines the information about the replica to send to the master.
Syntax

 

typedef int (*repl_session_plugin_reply_acquire_cb)(const char *repl_subtree, int is_total,
                                                   char **data_guid, struct berval **data);
Parameters

This function takes the following parameters:

Parameter Description
cookie Private data used by the plug-in. This is the value returned by the replication plug-in init function (if any) and passed to all plug-in functions.
repl_subtree Gives the subtree that is involved in replication.
data_guid Contains the identifier for the expected data.
data_guid Contains the data.

14.36.4. repl_session_plugin_post_acquire_cb

Posts the response from the replica to the master server.
Syntax

 

typedef int (*repl_session_plugin_post_acquire_cb)(void *cookie, const Slapi_DN *repl_subtree,
                                          int is_total, const char *data_guid, const struct berval *data);
Parameters

This function takes the following parameters:

Parameter Description
cookie Private data used by the plug-in. This is the value returned by the replication plug-in init function (if any) and passed to all plug-in functions.
repl_subtree Gives the subtree that is involved in replication.
data_guid Contains the identifier for the expected data.
data_guid Contains the data.

14.36.5. repl_session_plugin_recv_acquire_cb

Receives the data from the replica.
Syntax

 

typedef int (*repl_session_plugin_recv_acquire_cb)(const char *repl_subtree, int is_total,
                                          const char *data_guid, const struct berval *data);
Parameters

This function takes the following parameters:

Parameter Description
cookie Private data used by the plug-in. This is the value returned by the replication plug-in init function (if any) and passed to all plug-in functions.
repl_subtree Gives the subtree that is involved in replication.
data_guid Contains the identifier for the expected data.
data_guid Contains the data.

14.36.6. repl_session_plugin_destroy_agmt_cb

Destroys a replication agreement when the operation is complete.
Syntax

 

typedef void (*repl_session_plugin_destroy_agmt_cb)(void *cookie, const Slapi_DN *repl_subtree);
Parameters

This function takes the following parameters:

Parameter Description
cookie Private data used by the plug-in. This is the value returned by the replication plug-in init function (if any) and passed to all plug-in functions.
repl_subtree Gives the subtree that is involved in replication.

14.37. Synchronization Callbacks and Data Types

These typedef declarations are used for both directions of Directory Server and Active Directory synchronization and can be used for adding or modifying entries in both servers.

Table 14.18. WinSync Types

typedef Description
winsync_can_add_to_ad_cb Used to determine if a Directory Server entry should be added to the Active Directory server.
winsync_get_new_dn_cb Specifies a DN for a new entry being synced from the Active Directory server over to the Directory Server.
winsync_plugin_init_cb Initializes the synchronization plug-in.
winsync_pre_add_cb Called whenever a new entry is being added to the Directory Server.
winsync_pre_ad_mod_mods_cb Specifies modifications that must be synced over to the Active Directory server.
winsync_pre_mod_cb Sets the main entry points that allow the sync plug-in to intercept modifications between local and remote entries.
winsync_search_params_cb Sets the search parameters for the Active Directory and Directory Server instances, based on the sync agreement.

14.37.1. winsync_can_add_to_ad_cb

Sets a callbacks to determine if an entry in the Directory Server should be added to the Active Directory server if the entry does not already exist in the Windows domain.
Syntax

 

#include "slapi-plugin.h"
typedef int (*winsync_can_add_to_ad_cb)(void *cookie, const Slapi_Entry *local_entry, const Slapi_DN *remote_dn);
Parameters

This function takes the following parameters:

Parameter Description
cookie Private data used by the plug-in. This is the value returned by the Windows Sync plug-in init function (if any) and passed to all plug-in functions.
local_entry The Directory Server copy of the entry being checked by the server.
remote_dn The remote copy of the entry to add to the Active Directory server.
Returns

If the server is allowed to add the entry to the Active Directory server, then winsync_can_add_to_ad_cb declaration returns 16.

14.37.2. winsync_get_new_dn_cb

Specifies a DN for a new entry being synced from the Active Directory server over to the Directory Server instance.
When a new entry is created on the Active Directory server and it synced over to the Directory Server, it may be necessary to generate a new DN for the entry. This can result in a naming conflict between the name on one server and the generated name from the synchronization plug-in. This callback function allows the sync plug-in to set the new DN for the entry.
The map_entry_dn_inbound function is called to identify the DN for the new entry is needed. The winsync_plugin_call_pre_ds_add_* callbacks can also be used to set the DN for the new entry before it is stored in the Directory Server.
This data type is also used when an attribute with a DN as a value, such as owner or secretary, is synchronized.
Syntax

 

#include "slapi-plugin.h"
typedef void (*winsync_get_new_dn_cb)(void *cookie, const Slapi_Entry *rawentry, Slapi_Entry *ad_entry, char **new_dn_string,
  const Slapi_DN *ds_suffix, const Slapi_DN *ad_suffix);
Parameters

This function takes the following parameters:

Parameter Description
cookie Private data used by the plug-in. This is the value returned by the Windows Sync plug-in init function (if any) and passed to all plug-in functions.
rawentry The unprocessed Active Directory entry, as it is read directly from Active Directory. This entry is read-only.
ad_entry The processed Active Directory entry.
new_dn_string The given value of the DN for the new entry. The default value is created by the sync code using memory allocated by slapi_ch_malloc(). slapi_ch_free_string() is called to free this memory when it is not longer needed.
ds_suffix The Directory Server suffix being synchronized.
ad_suffix The Active Directory suffix being synchronized.
Returns

There are two possible returns:

  • For a Directory Server user, this returns 12.
  • For a Directory Server group, this returns 13.
See Also

  • winsync_plugin_call_pre_ds_add_*
  • map_entry_dn_inbound

14.37.3. winsync_plugin_init_cb

Initializes the synchronization plug-in.
Whenever synchronization begins, the sync plug-in defines this callback to initialize the other sync callbacks.
The Directory Server and Active Directory subtrees are passed in from the sync agreement as read-only attributes. The return value is private data for the sync plug-in which is passed with each sync callback. If the sync plug-in returns a value, the plug-in must define a winsync_plugin_destroy_agmt_cb callback so that the private data can be freed. This private data is passed to every other callback function as the void *cookie argument.
Syntax

 

#include "slapi-plugin.h"
typedef void * (*winsync_plugin_init_cb)(const Slapi_DN *ds_subtree, const Slapi_DN *ad_subtree);
Parameters

This function takes the following parameters:

Table 14.19. winsync_plugin_init_cb Parameters

Parameter Description
ds_subtree The Directory Server subtree being synchronized.
ad_subtree The Active Directory subtree being synchronized.
Returns

If the plug-in is successfully initialized, the server returns 1.

14.37.4. winsync_pre_add_cb

Called whenever a new entry is being added to the Directory Server after being synced over from the Active Directory server.
Syntax

 

#include "slapi-plugin.h"
typedef void (*winsync_pre_add_cb)(void *cookie, const Slapi_Entry *rawentry, Slapi_Entry *ad_entry, Slapi_Entry *ds_entry);
Parameters

This function takes the following parameters:

Table 14.20. winsync_pre_add_cb Parameters

Parameter Description
cookie Private data used by the plug-in. This is the value returned by the Windows Sync plug-in init function (if any) and passed to all plug-in functions.
rawentry The unprocessed Active Directory entry, as it is read directly from Active Directory. This entry is read-only.
ad_entry The processed Active Directory entry.
ds_entry The entry to be added to the Directory Server. Any modifications to the new entry should be made to this entry. This includes changing the DN, since the DN of this processed entry is used as the target DN for the final new entry in the Directory Server. This processed entry already has the default schema mapping applied.
Returns

There are two possible returns:

  • For a user, this returns 10.
  • For a group, this returns 11.

14.37.5. winsync_pre_ad_mod_mods_cb

Specifies modifications to be synced over to the Active Directory server from the results of an LDAP modify operation.
The plug-in may alter the list of modifications (specified as an array of LDAPMod* objects) before they are sent to Active Directory as an LDAP modify operation.
Syntax

 

#include "slapi-plugin.h"
typedef void (*winsync_pre_ad_mod_mods_cb)(void *cookie, const Slapi_Entry *rawentry, const Slapi_DN *local_dn, const Slapi_Entry *ds_entry, LDAPMod * const *origmods, Slapi_DN *remote_dn, LDAPMod ***modstosend);
Parameters

This function takes the following parameters:

Table 14.21. winsync_pre_ad_mod_mods_cb Parameters

Parameter Description
cookie Private data used by the plug-in. This is the value returned by the Windows Sync plug-in init function (if any) and passed to all plug-in functions.
rawentry The unprocessed Active Directory entry, as it is read directly from Active Directory. This entry is read-only. This can be NULL.
local_dn The original Directory Server DN specified in the modification.
ds_entry The Directory Server entry which is the source of these modifications. The modifications have already been made to this entry.
origmods The list of actual modifications made to the local entry.
remote_dn The DN of the entry on the Active Directory server to which to write the changes; this may be calculated by the sync plug-in.
modstosend The list of modifications which will be written to the Active Directory entry. The changes being sent have the attributes mapped between Directory Server and Active Directory schema so that the changes to be sent fit with Active Directory schema.
Returns

There are two possible returns:

  • If modifications are applied to a user, this returns 14.
  • If modifications are applied to a group, this returns 15.

14.37.6. winsync_pre_mod_cb

These callbacks are called as the result of an LDAP add operation, when the Win Sync code determines that the destination entry already exists. In that case, the Win Sync code converts the add operation to a modify operation, calculates the difference between the entries, and formats those differences as a list of LDAP modify operations, specified in the smods parameter. The PRE_AD functions are used when the destination is the Active Directory entry, and the PRE_DS functions are used when the destination is the Directory Server entry.
Syntax

 

#include "slapi-plugin.h"
typedef void (*winsync_pre_mod_cb)(void *cookie, const Slapi_Entry *rawentry, Slapi_Entry *ad_entry, Slapi_Entry *ds_entry, Slapi_Mods *smods, int *do_modify);
Parameters

This function takes the following parameters:

Table 14.22. winsync_pre_mod_cb Parameters

Parameter Description
cookie Private data used by the plug-in. This is the value returned by the Windows Sync plug-in init function (if any) and passed to all plug-in functions.
rawentry The unprocessed Active Directory entry, as it is read directly from Active Directory. This entry is read-only.
ad_entry The processed Active Directory entry. This DN is set if the modify is against the Active Directory entry.
ds_entry The entry to be added to the Directory Server. This DN is set if the modify is against the Directory Server entry.
smods
Pointer to an initialized Slapi_Mod. These contain the post-processing modifications. These modifications should be updated by the sync plug-in to perform any mappings or other changes.
do_modify Indicates whether an operation will be performed on the entry. If there are changes to be synced to the entry or if the sync plug-in has changed any of the smods, then this value is true, meaning that an operation should be performed on the entry. If all of the smods were removed by the sync plug-in, meaning there is no operation to perform, then the value is false.
Returns

There are four possible returns:

  • If modifications have been performed on an Active Directory user, this returns 6.
  • If modifications have been performed on an Active Directory group, this returns 7.
  • If modifications have been performed on a Directory Server user, this returns 8.
  • If modifications have been performed on a Directory Server group, this returns 9.

14.37.7. winsync_search_params_cb

Allows configurable search parameters for searches of the Directory Server and Active Directory instances during synchronization.
Syntax

 

#include "slapi-plugin.h"
typedef void (*winsync_search_params_cb)(void *cookie, const char *agmt_dn, char **base, int *scope, char **filter, char ***attrs, LDAPControl ***serverctrls);
#define WINSYNC_PLUGIN_DIRSYNC_SEARCH_CB 2 
#define WINSYNC_PLUGIN_PRE_AD_SEARCH_CB 3
#define WINSYNC_PLUGIN_PRE_DS_SEARCH_ENTRY_CB 4
#define WINSYNC_PLUGIN_PRE_DS_SEARCH_ALL_CB 5
  • WINSYNC_PLUGIN_DIRSYNC_SEARCH_CB 2 is called when the Win Sync code does the DirSync search of Active Directory looking for the initial list of entries during the init phase or for new changes during the incremental phase.
  • WINSYNC_PLUGIN_PRE_AD_SEARCH_CB 3 is called when the Win Sync code needs to search for an Active Directory entry to get more information from it during the sync process. This is used to get the rawentry or the ad_entry passed as a parameter to many of the Win Sync functions.
  • WINSYNC_PLUGIN_PRE_DS_SEARCH_ENTRY_CB 4 is called when the Win Sync code needs to search for a Directory Server entry to get more information from it during the sync process. This is used to get the ds_entry passed as a parameter to many of the Win Sync functions.
  • WINSYNC_PLUGIN_PRE_DS_SEARCH_ALL_CB 5 is called when the Win Sync code does the initial internal search of Directory Server to get all of the entries that will be synced to Active Directory.
Parameters

This function takes the following parameters:

Table 14.23. winsync_search_params_cb Parameters

Parameter Description
cookie Private data used by the plug-in. This is the value returned by the Windows Sync plug-in init function (if any) and passed to all plug-in functions.
agmt_dn The original Active Directory base DN which is specified in the sync agreement.
scope The original scope of the search on the Active Directory server. This value is explicitly set. For example:
*scope = LDAP_SCOPE_SUBTREE;
base The base DN on the Directory Server to search for synchronization. To set this value, free the base first using slapi_ch_free_string() and allocate new memory using one of the slapi memory allocation functions. This value is then freed using slapi_ch_free_string() after use.
filter The filter to use to search for entries in the Directory Server base . To set the filter, free it along with the base using slapi_ch_free_string(). For example:
slapi_ch_free_string(filter);
*base = slapi_ch_strdup("(objectclass=foobar)");
attrs Pointer to the Slapi_Attr structure representing the first attribute in the entry. This can be either NULL or a null-terminated array of strings. The attributes can be added using slapi_ch_array_add. For example:
slapi_ch_array_add(attrs, slapi_ch_strdup("myattr"));
attrs are freed using slapi_ch_array_free, so the caller must own the memory.
serverctrls Pointer to the LDAPControl* structure. This can be either NULL or a null-terminated array of controls. To define the LDAPControl, use slapi_add_control_ext:
slapi_add_control_ext(serverctrls, mynewctrl, 1 / add a copy /);
serverctrls are freed with ldap_controls_free, so the caller must own memory.
Returns

There are four possible returns:

  • For a DirSync search, this returns 2.
  • To search the Active Directory subtree, this returns 3.
  • To search the Directory Server subtree, this returns 4.
  • To search the Directory Server from the base DN, this returns 5.

Part IV. Function Reference

This part contains reference information on Red Hat Directory Server (Directory Server) server plug-in API. The server plug-in API includes the above functions. Each chapter summarizes the frontend functions in a table followed by the function details.

Chapter 15. Distribution Routines

This chapter contains reference information on distribution routines.

Table 15.1. Distribution Routines

Function Description
distribution_plugin_entry_point() Allows for backend distribution.

15.1. distribution_plugin_entry_point()

Description

Backend distribution is the capability to span the LDAP subtree contents under a specified DIT node into multiple backends in the same server and/or database links to other servers. Under such a configuration, this function is responsible for deciding where the database or database link under the DIT node will be applied. This function will be called for every operation reaching a DIT node, including subtree search operations that are started above the node.

This function can only be called if the server has been configured to take advantage of such capability.
Returns

This function should return the index of the backend in the mtn_be_names table that is used to resolve the current operation. For search operations, SLAPI_BE_ALL_BACKENDS can be returned to specify that backends must be searched. The use of SLAPI_BE_ALL_BACKENDS for non-search operations is not supported and may give random results.

Syntax

 

#include "slapi-plugin.h"
int distribution_plugin_entry_point (Slapi_PBlock *pb, Slapi_DN *target_dn, char **mtn_be_names, int be_count, Slapi_DN * node_dn);
Parameters

This function takes the following parameters:

pb Pointer to the parameter block of the operation.
target_dn Pointer to the target DN of the operation.
mtn_be_names Pointer to the list of names of backends declared for this node.
be_count The number of backends declared under a specified DIT node.
node_dn DN of the node where the distribution function is set.

Chapter 16. Functions for Access Control

This chapter contains reference information on access control routines.

Table 16.1. Access Control Routines

Function Description
slapi_access_allowed() Determines if the user who is requesting the current operation has the access rights to perform an operation on a given entry, attribute, or value.
slapi_acl_check_mods() Determines if a user has the rights to perform the specified modifications on an entry.
slapi_acl_verify_aci_syntax() Determines whether the access control items (ACIs) on an entry are valid.

16.1. slapi_access_allowed()

Description

Call this function to determine if a user has access rights to a specified entry, attribute, or value. The function performs this check for users who request the operation that invokes this plug-in.

For example, suppose you are writing a pre-operation plug-in for the add operation. You can call this function to determine if users have the proper access rights before they can add an entry to the directory.
As part of the process of determining if the user has access rights, the function does the following:
  • Checks to see if the user requesting the operation is the root DN.
If so, the function returns LDAP_SUCCESS. (The root DN has permission to perform any operation.)
  • Gets information about the operation being requested, the connection to the client, and the backend database where directory information is stored.
    • If for some reason the function cannot determine which operation is being requested, the function returns LDAP_OPERATIONS_ERROR.
    • If no connection to a client exists (in other words, if the request for the operation was made by the server or its backend), the function returns LDAP_SUCCESS. (The server and its backend are not restricted by access control lists.)
    • If the backend database is read-only and the request is checking for write access (SLAPI_ACL_WRITE), the function returns LDAP_UNWILLING_TO_PERFORM.
  • Determines if the user requesting the operation is attempting to modify his or her own entry.
ACLs can be set up to allow users the rights to modify their own entries. The slapi_access_allowed() function checks for this condition.
The caller must ensure that the backend specified in the pblock is set prior to calling this function. For example:
be = slapi_be_select( slapi_entry_get_sdn_const( seObjectEntry ));
				if ( NULL == be ) {
				cleanup("backend selection failed for entry: \"%s\"\n",
				szObjectDN);
				slapi_send_ldap_result( pb, LDAP_NO_SUCH_OBJECT, NULL,
				" Object could not be found", 0, NULL );
				return( SLAPI_PLUGIN_EXTENDED_SENT_RESULT );
				}
				slapi_pblock_set( pb, SLAPI_BACKEND, be );
				nAccessResult = slapi_access_allowed( pb, seObjectEntry, "*", bval, SLAPI_ACL_DELETE);
Determines if a user (who is requesting the current operation) has the access rights to perform an operation on a given entry, attribute, or value.
Syntax

 

#include "slapi-plugin.h"
int slapi_access_allowed( Slapi_PBlock *pb, Slapi_Entry *e, char *attr, struct berval *val, int access );
Parameters

This function takes the following parameters:

pb Parameter block passed into this function.
e Entry for which you want to check the access rights.
attr Attribute for which you want to check the access rights.
val Pointer to the berval structure containing the value for which you want to check the access rights.
access Type of access rights for which you want to check; for example, to check for write access, pass SLAPI_ACL_WRITE as the value of this argument.
The value of the access argument can be one of the following:
SLAPI_ACL_ADD Permission to add a specified entry.
SLAPI_ACL_COMPARE Permission to compare the specified values of an attribute in an entry.
SLAPI_ACL_DELETE Permission to delete a specified entry.
SLAPI_ACL_READ Permission to read a specified attribute.
SLAPI_ACL_SEARCH Permission to search on a specified attribute or value.
SLAPI_ACL_WRITE Permission to write a specified attribute or value or permission to rename a specified entry.
Returns

This function returns one of the following values:

  • LDAP_SUCCESS if the user has the specified rights to the entry, attribute, or value.
  • LDAP_INSUFFICIENT_ACCESS if the user does not have the specified rights to the entry, attribute, or value.
If a problem occurs during processing, the function will return one of the following error codes:
LDAP_OPERATIONS_ERROR An error occurred while executing the operation. This error can occur if, for example, the type of access rights you've specified are not recognized by the server (in other words, you did not pass a value from the previous table).
LDAP_INVALID_SYNTAX Invalid syntax was specified. This error can occur if the ACL associated with an entry, attribute, or value uses the wrong syntax.
LDAP_UNWILLING_TO_PERFORM The Directory Server is unable to perform the specified operation. This error can occur if, for example, you are requesting write access to a read-only database.

16.2. slapi_acl_check_mods()

Description

Call this function to determine if a user has access rights to modify the specified entry. The function performs this check for users who request the operation that invokes this plug-in.

Suppose you are writing a database plug-in. You can call this function to determine if users have the proper access rights before they can add, modify, or delete entries from the database.
As part of the process of determining if the user has access rights, the slapi_acl_check_mods() function does the following:
  • Checks if access control for the directory is disabled (for example, if the dse.ldif file contains the directive access control off).
If access control is disabled, the function returns LDAP_SUCCESS.
  • For each value in each attribute specified in the LDAPMod array, the function determines if the user has permissions to write to that value. Essentially, the function calls slapi_acl_check_mods() with SLAPI_ACL_WRITE as the access right to check.
    • If for some reason the function cannot determine which operation is being requested, the function returns LDAP_OPERATIONS_ERROR.
    • If no connection to a client exists (in other words, if the request for the operation was made by the server orits backend), the function returns LDAP_SUCCESS. (The server and its backend are not restricted by access control lists.)
    • If the backend database is read-only and the request is checking for write access (SLAPI_ACL_WRITE), the function returns LDAP_UNWILLING_TO_PERFORM.
Syntax

 

#include "slapi-plugin.h"
int slapi_acl_check_mods( Slapi_PBlock *pb, Slapi_Entry *e, LDAPMod **mods, char **errbuf );
Parameters

This function takes the following parameters:

pb Parameter block passed into this function.
e Entry for which you want to check the access rights.
mods Array of LDAPMod structures that represent the modifications to be made to the entry.
errbuf Pointer to a string containing an error message if an error occurs during the processing of this function.
Returns

This function returns one of the following values:

  • LDAP_SUCCESS if the user has write permission to the values in the specified attributes.
  • LDAP_INSUFFICIENT_ACCESS if the user does not have write permission to the values of the specified attribute.
  • If a problem occurs during processing, the function will return one of the following error codes:
LDAP_OPERATIONS_ERROR An error occurred while executing the operation.
LDAP_INVALID_SYNTAX Invalid syntax was specified. This error can occur if the ACL associated with an entry, attribute, or value uses the wrong syntax.
LDAP_UNWILLING_TO_PERFORM The Directory Server is unable to perform the specified operation. This error can occur if, for example, you are requesting write access to a read-only database.
Memory Concerns

You must free the errbuf buffer by calling slapi_ch_free() when you are finished using the error message.

16.3. slapi_acl_verify_aci_syntax()

Description

Determines whether the access control items (ACIs) on an entry are valid.

Syntax

 

#include "slapi-plugin.h"
int slapi_acl_verify_aci_syntax (Slapi_Entry *e, char **errbuf);
Parameters

This function takes the following parameters:

e Entry for which you want to check the ACIs.
errbuf Pointer to the error message returned if the ACI syntax is invalid.
Returns

This function returns one of the following values:

  • 0 if successful.
  • -1 if an error occurs.
Memory Concerns

You must free the errbuf buffer by calling slapi_ch_free() when you are finished using the error message.

See Also

slapi_ch_free()

Chapter 17. Functions for Internal Operations and Plug-in Callback

This chapter contains reference information on routines for internal operations and plug-in callbacks. These functions can be used for internal operations based on DN as well as on unique ID. These functions should be used by all new plug-ins, and, preferably, old plug-ins should be changed to use them to take advantage of new plug-in configuration capabilities and to use an extensible interface.

Table 17.1. Internal Operations and Plug-in Callback Routines

Function Description
slapi_add_internal_pb() Performs an LDAP add operation based on a parameter block to add a new directory entry.
slapi_delete_internal_pb() Performs an LDAP delete operation based on a parameter block to remove a directory entry.
slapi_free_search_results_internal() Frees search results.
slapi_modify_internal_pb() Performs an LDAP modify operation based on a parameter block to modify a directory entry.
slapi_modrdn_internal_pb() Performs an LDAP modify RDN operation based on a parameter block to rename a directory entry.
slapi_search_internal_callback_pb() Performs an LDAP search operation based on a parameter block to search the directory.
slapi_search_internal_get_entry() Performs an internal search operation to read one entry.
slapi_search_internal_pb() Performs an LDAP search operation based on a parameter block to search the directory.

17.1. slapi_add_internal_pb()

Description

The function performs an internal LDAP add operation based on a parameter block. The parameter block should be initialized by calling slapi_add_internal_set_pb() or slapi_add_entry_internal_set_pb().

Syntax

 

#include "slapi-plugin.h"
int slapi_add_internal_pb ( Slapi_PBlock *pb );
Parameters

This function takes the following parameter:

pb A parameter block that has been initialized using slapi_add_internal_set_pb().
Returns

This function returns one of the following values:

  • 0 if successful.
  • -1 if an error occurs. If -1 is returned, the SLAPI_PLUGIN_INTOP_RESULT field of the parameter block should be consulted to determine the precise LDAP result code.
Memory Concerns

None of the parameters that are passed slapi_add_internal_set_pb() are altered or consumed by this function. The entry parameter that is passed to slapi_add_entry_internal_set_pb() is consumed by a successful call to this function.

17.2. slapi_delete_internal_pb()

Description

This function performs an internal delete operation based on a parameter block to remove a directory entry. The parameter block should be initialized by calling slapi_delete_internal_set_pb().

Syntax

 

#include "slapi-plugin.h"
int slapi_delete_internal_pb(Slapi_PBlock *pb);
Parameters

This function takes the following parameter:

pb A parameter block that has been initialized using slapi_delete_internal_set_pb().
Returns

This function returns one of the following values:

  • 0 if successful.
  • -1 if an error occurs. If -1 is returned, the SLAPI_PLUGIN_INTOP_RESULT field of the parameter block should be consulted to determine the precise LDAP result code.
Memory Concerns

None of the parameters that are passed to slapi_delete_internal_set_pb() are altered or consumed by this function.

17.3. slapi_free_search_results_internal()

Description

Frees search results returned by the slapi_search_internal_pb() and slapi_search_internal_callback_pb() functions.

This function must be called when you are finished with the entries before freeing the pblock.
Syntax

 

#include "slapi-plugin.h"
void slapi_free_search_results_internal(Slapi_PBlock *pb);
Parameters

This function takes the following parameters:

pb Parameter block returned by the slapi_search_internal_pb() and slapi_search_internal_callback_pb() functions.

17.4. slapi_modify_internal_pb()

Description

This function performs an internal modify operation based on a parameter block. The parameter block should be initialized by calling slapi_modify_internal_set_pb().

Syntax

 

#include "slapi-plugin.h"
int slapi_modify_internal_pb(Slapi_PBlock *pb);
Parameters

This function takes the following parameter:

pb A parameter block that has been initialized using slapi_modify_internal_set_pb().
Returns

This function returns one of the following values:

  • 0 if successful.
  • -1 if an error occurs. If -1 is returned, the SLAPI_PLUGIN_INTOP_RESULT field of the parameter block should be consulted to determine the precise LDAP result code.
Memory Concerns

None of the parameters that are passed to slapi_modify_internal_set_pb() are altered or consumed by this function.

17.5. slapi_modrdn_internal_pb()

Description

This function performs an internal modify RDN operation based on a parameter block to rename a directory entry. The parameter block should be initialized by calling slapi_rename_internal_set_pb().

Syntax

 

#include "slapi-plugin.h"
int slapi_modrdn_internal_pb(Slapi_PBlock *pb);
Parameters

This function takes the following parameter:

pb A parameter block that has been initialized using slapi_rename_internal_set_pb().
Returns

This function returns one of the following values:

  • 0 if successful.
  • -1 if an error occurs. If -1 is returned, the SLAPI_PLUGIN_INTOP_RESULT field of the parameter block should be consulted to determine the precise LDAP result code.
Memory Concerns

None of the parameters that are passed to slapi_modrdn_internal_set_pb() are altered or consumed by this function.

17.6. slapi_search_internal_callback_pb()

Description

Performs an LDAP search operation based on a parameter block to search the directory. Unlike slapi_search_internal_pb(), this function allows you to specify callback functions that are invoked when the search operation finds matching entries or entries with referrals.

Syntax

 

#include "slapi-plugin.h"
int slapi_search_internal_callback_pb(Slapi_PBlock *pb, void *callback_data, plugin_result_callback prc, plugin_search_entry_callback psec, plugin_referral_entry_callback prec);
Parameters

This function takes the following parameters:

pb A parameter block that has been initialized using slapi_seq_internal_callback_set_pb().
callback_data A pointer to arbitrary plug-in or operation-specific data that you would like to pass to your callback functions.
prc Callback function that the server calls to send result codes. The function must have the prototype specified by plugin_result_callback.
psec Callback function that the server calls when finding a matching entry in the directory. The function must have the prototype specified by plugin_search_entry_callback.
prec Callback function that the server calls when finding an entry that contains LDAPv3 referrals. The function must have the prototype specified by plugin_referral_entry_callback.
Returns

This function returns one of the following values:

  • 0 if successful.
  • -1 if an error occurs. If -1 is returned, the SLAPI_PLUGIN_INTOP_RESULT field of the parameter block should be consulted to determine the precise LDAP result code.
Memory Concerns

The entries passed to the search entry callback function do not need to be freed. If you need to access an entry after returning from the callback function, call slapi_entry_dup() to make a copy.

The referral URLs passed to the referral entry callback function do not need to be freed. If you need to access a referral string after returning from the callback function, call slapi_ch_strdup() to make a copy.
You do not need to call slapi_free_search_results_internal() after calling slapi_search_internal_callback_pb.

17.7. slapi_search_internal_get_entry()

Description

This function performs an internal search operation to read one entry; that is, it performs a base object search. If an entry named by dn is found, the ret_entry pointer will be set to point to a copy of the entry that contains the attribute values specified by the attrs parameter.

Syntax

 

#include "slapi-plugin.h"
int  slapi_search_internal_get_entry( Slapi_DN *dn, char ** attrs, Slapi_Entry **ret_entry , void * component_identity)
Parameters

This function takes the following parameters:

dn The DN of the entry to be read.
attrs A NULL terminated array of attribute types to return from entries that match filter. If you specify a NULL, all attributes will be returned.
ret_entry The address of a pointer to receive the entry if it is found.
component_identity A plug-in or component identifier. This value can be obtained from the SLAPI_PLUGIN_IDENTITY field of the parameter block that is passed to your plug-in initialization function.
Returns

This function returns the LDAP result code for the search operation and the results of slapi_search_internal_get_entry_ext.

Memory Concerns

The returned entry (*ret_entry) should be freed by calling slapi_entry_free().

See Also

 

17.8. slapi_search_internal_pb()

This function performs an internal LDAP search based on a parameter block to search the directory. The parameter block should be initialized by calling the slapi_search_internal_set_pb() function.
Syntax

 

#include "slapi-plugin.h"
int slapi_search_internal_pb(Slapi_PBlock *pb);
Parameters

This function takes the following parameter:

pb A parameter block that has been initialized using slapi_search_internal_set_pb().
Returns

This function returns one of the following values:

  • 0 if successful.
  • -1 if an error occurs. If -1 is returned, the SLAPI_PLUGIN_INTOP_RESULT field of the parameter block should be consulted to determine the precise LDAP result code.
Memory Concerns

slapi_free_search_results_internal() should be called to dispose of any entires and other items that were allocated by a call to slapi_search_internal_pb().

Chapter 18. Functions for Setting Internal Operation Flags

This chapter contains reference information on routines for setting internal-operation flags.

Table 18.1. Internal Operation Flag Routines

Function
Description
Sets up a parameter block so that it can be used by slapi_add_internal_pb() for an internal add operation.
Sets up a parameter block so that it can be used by slapi_add_internal_pb() for an internal add operation; the entry is constructed from a DN and a set of attributes.
Sets up a parameter block so that it can be used by slapi_delete_internal_pb() for an internal delete operation.
Sets up a parameter block so that it can be used by slapi_modify_internal_pb() for an internal modify operation.
Sets up a parameter block so that it can be used by slapi_modrdn_internal_pb() for an internal rename operation.
Sets up a parameter block so that it can be used by slapi_search_internal_pb() for an internal search operation.
Performs an internal sequential access operation.
Sets up a parameter block for use by slapi_seq_internal_callback_pb() for an internal sequential-access operation.

18.1. slapi_add_entry_internal_set_pb()

Description

This function populates parameters in the pblock structure so that it can be used by slapi_add_internal_pb() for an internal add operation.

Syntax

 

#include "slapi-plugin.h"
void slapi_add_entry_internal_set_pb(Slapi_PBlock *pb, Slapi_Entry *e, LDAPControl **controls, Slapi_ComponentId *plugin_identity, int operation_flags);
Parameters

This function takes the following parameters:

pb Parameter block populated with add parameters.
e Entry to be added.
controls List of controls associated with the operation.
plugin_identity Plug-in identity; a cookie that identifies the plug-in to the Directory Server during an internal operation. This cookie is used by the server to retrieve the plug-in configuration in order to determine whether to allow the operation and which actions to take during the operation processing. Plug-in identity is passed to the plug-in initialization function in the SLAPI_PLUGIN_IDENTITY pblock parameter. A plug-in must save this information and pass it to every internal operation issued by the plug-in.
operation_flags Actions taken during operation processing.

18.2. slapi_add_internal_set_pb()

Description

This function sets up a parameter block so that it can be used by slapi_add_internal_pb() for an internal add operation. This function is similar to slapi_add_entry_internal_set_pb() except that it constructs the entry from a DN and a set of attributes. The function sets pblock to contain the following data:

  • SLAPI_TARGET_DN set to DN of the new entry.
  • SLAPI_CONTROLS_ARG set to request controls, if present.
  • SLAPI_ADD_ENTRY set to Slapi_Entry to add.
Syntax

 

#include "slapi-plugin.h"
int slapi_add_internal_set_pb(Slapi_PBlock *pb, const Slapi_DN *dn, LDAPMod **attrs, LDAPControl **controls,
 Slapi_ComponentId *plugin_identity, int operation_flags);
Parameters

This function takes the following parameters:

pb Parameter block populated with add parameters.
dn Entry DN.
attrs Entry attributes.
controls List of controls associated with the operation.
plugin_identity Plug-in identity; a cookie that identifies the plug-in to the Directory Server during an internal operation. This cookie is used by the server to retrieve the plug-in configuration in order to determine whether to allow the operation and which actions to take during the operation processing. Plug-in identity is passed to the plug-in initialization function in the SLAPI_PLUGIN_IDENTITY pblock parameter. A plug-in must save this information and pass it to every internal operation issued by the plug-in.
operation_flags Actions taken during operation processing.
Returns

This function returns LDAP_SUCCESS or one of the LDAP error codes if the entry cannot be constructed from the specified attributes due to constraint violation.

18.3. slapi_delete_internal_set_pb()

Description

This function populates pblock to contain data for use by slapi_delete_internal_pb() for an internal delete operation.

For unique identifier-based operation:
  • SLAPI_TARGET_DN set to the DN that allows to select the right backend.
  • SLAPI_TARGET_UNIQUEID set to the unique ID of the entry.
  • SLAPI_CONTROLS_ARG set request controls, if present.
For DN-based search:
  • SLAPI_TARGET_DN set to the entry DN.
  • SLAPI_CONTROLS_ARG set to request controls, if present.
Syntax

 

#include "slapi-plugin.h"
void slapi_delete_internal_set_pb (Slapi_PBlock *pb, const Slapi_DN *dn, LDAPControl **controls, 
 const char *uniqueid, Slapi_ComponentId *plugin_identity, int operation_flags);
Parameters

This function takes the following parameters:

pb Parameter block populated with delete parameters.
dn DN of the entry to be removed. For unique ID operation, this parameter is used to select the correct backend.
controls List of controls associated with the operation.
uniqueid Unique identifier of the entry to be removed. All directory entries contain a unique identifier. Unlike the distinguished name (DN), the unique identifier of an entry never changes, providing a good way to refer unambiguously to an entry in a distributed/replicated environment.
plugin_identity Plug-in identity; a cookie that identifies the plug-in to the Directory Server during an internal operation. This cookie is used by the server to retrieve the plug-in configuration in order to determine whether to allow the operation and which actions to take during the operation processing. Plug-in identity is passed to the plug-in initialization function in the SLAPI_PLUGIN_IDENTITY pblock parameter. A plug-in must save this information and pass it to every internal operation issued by the plug-in.
operation_flags Actions taken during operation processing.

18.4. slapi_modify_internal_set_pb()

Description

This function populates pblock to contain data for use by slapi_modify_internal_pb() for an internal modify operation.

For unique ID-based operation:
  • SLAPI_TARGET_DN set to the DN that allows to select the right backend.
  • SLAPI_TARGET_UNIQUEID set to the unique ID of the entry.
  • SLAPI_MODIFY_MODS set to the mods.
  • SLAPI_CONTROLS_ARG set to request controls, if present.
For DN-based search:
  • SLAPI_TARGET_DN set to the entry DN.
  • SLAPI_MODIFY_MODS set to the mods.
  • SLAPI_CONTROLS_ARG set to request controls, if present.
Syntax

 

#include "slapi-plugin.h"
void slapi_modify_internal_set_pb(Slapi_PBlock *pb, const Slapi_DN *dn, LDAPMod **mods, 
 LDAPControl **controls, const char *uniqueid, Slapi_ComponentId *plugin_identity, int operation_flags);
Parameters

This function takes the following parameters:

pb Parameter block populated with modify parameters.
dn DN of the entry to be modified. For unique ID operation, this parameter is used to select the correct backend.
mods Modifications to be applied to the entry.
controls List of controls associated with the operation.
uniqueid Unique identifier of the entry to be modified. All directory entries contain a unique identifier. Unlike the distinguished name (DN), the unique identifier of an entry never changes, providing a good way to refer unambiguously to an entry in a distributed/replicated environment.
plugin_identity Plug-in identity; a cookie that identifies the plug-in to the Directory Server during an internal operation. This cookie is used by the server to retrieve the plug-in configuration in order to determine whether to allow the operation and which actions to take during the operation processing. Plug-in identity is passed to the plug-in initialization function in the SLAPI_PLUGIN_IDENTITY pblock parameter. A plug-in must save this information and pass it to every internal operation issued by the plug-in.
operation_flags Actions taken during operation processing.

18.5. slapi_rename_internal_set_pb()

Description

This function populates pblock with parameters for use by slapi_modrdn_internal_pb() for an internal rename operation. The function sets the parameter block to contain the following data.

Syntax

 

#include "slapi-plugin.h" 
void slapi_rename_internal_set_pb(Slapi_PBlock *pb, const char *olddn, const char *newrdn, const char *newsuperior, int deloldrdn, 
LDAPControl **controls, const char *uniqueid, Slapi_ComponentId *plugin_identity, int operation_flags);
Parameters

This function takes the following parameters:

pb Parameter block populated with rename parameters.
olddn DN of the entry to be renamed. For unique ID operation, this parameter is used to select the correct backend.
newrdn New RDN of the entry.
newsuperior New entry superior, moddn operation only.
deloldrdn Specifies whether the old RDN should be removed or left as a non-DN attribute.
controls List of controls associated with the operation.
uniqueid Unique identifier of the entry to be renamed. All directory entries contain a unique identifier. Unlike the distinguished name (DN), the unique identifier of an entry never changes, providing a good way to refer unambiguously to an entry in a distributed/replicated environment.
plugin_identity Plug-in identity; a cookie that identifies the plug-in to the Directory Server during an internal operation. This cookie is used by the server to retrieve the plug-in configuration in order to determine whether to allow the operation and which actions to take during the operation processing. Plug-in identity is passed to the plug-in initialization function in the SLAPI_PLUGIN_IDENTITY pblock parameter. A plug-in must save this information and pass it to every internal operation issued by the plug-in.
operation_flags Actions taken during operation processing.
For unique ID-based operation:
  • SLAPI_TARGET_DN set to the DN that allows to select the right backend.
  • SLAPI_TARGET_UNIQUEID set to the uniqueid of the entry.
  • SLAPI_MODRDN_NEWRDN set to the new RDN of the entry.
  • SLAPI_MODRDN_DELOLDRDN indicates whether the old RDN should be kept in the entry.
  • SLAPI_CONTROLS_ARG set to request controls, if present.
For DN-based search:
  • SLAPI_TARGET_DN set to the entry DN.
  • SLAPI_MODRDN_NEWRDN set to the new RDN of the entry.
  • SLAPI_MODRDN_DELOLDRDN indicates whether the old RDN should be kept in the entry.
  • SLAPI_CONTROLS_ARG set to request controls, if present.

18.6. slapi_search_internal_set_pb()

This function sets up the parameter block, for subsequent use by slapi_search_internal_pb(), to contain the following data for an internal search operation.
For unique ID-based search:
  • SLAPI_TARGET_DN set to the DN that allows to select the right backend.
  • SLAPI_TARGET_UNIQUEID set to the unique ID of the entry.
For DN-based search:
  • SLAPI_TARGET_DN set to the search base.
  • SLAPI_SEARCH_SCOPE set to the search scope.
  • SLAPI_SEARCH_STRFILTER set to the search filter.
  • SLAPI_CONTROLS_ARG set to request controls, if present.
  • SLAPI_SEARCH_ATTRS set to the list of attributes to return.
  • SLAPI_SEARCH_ATTRSONLY indicates whether attribute values should be returned.
Syntax

 

#include "slapi-plugin.h"
void slapi_search_internal_set_pb(Slapi_PBlock *pb, const char *base, int scope, const char *filter, char **attrs, 
int attrsonly, LDAPControl **controls, const char *uniqueid, Slapi_ComponentId *plugin_identity, int operation_flags);
Parameters

This function takes the following parameters:

pb Parameter block that is populated with search parameters.
base Search base.
scope Search scope (LDAP_SCOPE_SUBTREE, etc.).
filter Search filter.
attrs Attributes to be returned.
attrsonly Flag specifying whether to return just attribute names or names and values.
controls List of controls associated with the operation.
uniqueid Unique identifier of the entry. Non-NULL value indicates unique ID-based search. In this case, scope and filter are ignored; however, base is still required and is used to select the correct backend. All directory entries contain a unique identifier. Unlike the distinguished name (DN), the unique identifier of an entry never changes, providing a good way to refer unambiguously to an entry in a distributed/replicated environment.
plugin_identity Plug-in identity; a cookie that identifies the plug-in to the Directory Server during an internal operation. This cookie is used by the server to retrieve the plug-in configuration in order to determine whether to allow the operation and which actions to take during the operation processing. Plug-in identity is passed to the plug-in initialization function in the SLAPI_PLUGIN_IDENTITY pblock parameter. A plug-in must save this information and pass it to every internal operation issued by the plug-in.
operation_flags Actions taken during operation processing.
Memory Concerns

The controls passed with slapi_search_internal_set_pb() must be an allocated array. Additionally, this array must be freed by slapi_pblock_destroy().

If the user passes memory allocated on the stack or frees the controls himself, then when slapi_pblock_destroy() is called, the function can double-free the memory or corrupt the memory structures. This potentially leads to segfaults or other problems when the allocated memory is taken by any Slapi_* function.

18.7. slapi_seq_internal_callback_pb()

Description

This function performs internal sequential access operation.

Syntax

 

#include "slapi-plugin.h"
int slapi_seq_internal_callback_pb(Slapi_PBlock *pb, void *callback_data, 
 plugin_result_callback res_callback, plugin_search_entry_callback srch_callback, plugin_referral_entry_callback ref_callback);
Parameters

This function takes the following parameters:

pb Parameter block initialized with operation parameters. The easiest way to provide required parameters is by calling slapi_seq_internal_callback_pb() function. Parameters can also be set directly.
callback_data Data passed to the callback functions.
res_callback Function called once the search is complete.
srch_callback Function called for each entry returned.
ref_callback Function called for each referral returned.
Returns

This function returns 0 on success, -1 on error.

18.8. slapi_seq_internal_set_pb()

Description

This function sets up pblock for use by slapi_seq_internal_callback_pb() for an internal, sequential-access operation; the function sets up the parameter block contain the following data:

  • SLAPI_SEARCH_TARGET set to the search base.
  • SLAPI_ORIGINAL_TARGET_DN preserves the DN that was sent from the client (this DN is normalized as it is processed by SLAPI_SEARCH_TARGET); this value is read-only.
  • SAPI_SEQ_TYPE set to the sequential-access type (SLAPI_SEQ_FIRST, SLAPI_SEQ_NEXT, and so on.)
  • SLAPI_SEQ_ATTRNAME defines attribute value assertion relative to which access is performed.
  • SLAPI_SEQ_VAL defines attribute value assertion relative to which access is performed.
  • SLAPI_CONTROLS_ARG set to request controls, if present.
  • SLAPI_SEARCH_ATTRS set to the list of attributes to return.
  • SLAPI_SEARCH_ATTRSONLY indicates whether attribute values should be returned.
Syntax

#include "slapi-plugin.h"
void slapi_seq_internal_set_pb(Slapi_PBlock *pb, char *ibase, int type, char *attrname, char *val, 
char **attrs, int attrsonly, LDAPControl **controls, Slapi_ComponentId *plugin_identity, int operation_flags);

Parameters

This function takes the following parameters:

pb Parameter block initialized with operation parameters. The easiest way to provide required parameters is by calling slapi_seq_internal_callback_pb() function. Parameters can also be set directly.
callback_data Data passed to the callback functions.
res_callback Function called once the search is complete.
srch_callback Function called for each entry returned.
ref_callback Function called for each referral returned.

Chapter 19. Functions for Handling Attributes

This chapter contains reference information on attribute routines.

Table 19.1. Attribute Routines

Function Description
slapi_attr_add_value() Adds a value to an attribute.
slapi_attr_basetype() Returns the base type of an attribute.
slapi_attr_dup() Duplicates an attribute.
slapi_attr_first_value() Gets the first value of an attribute.
slapi_attr_flag_is_set() Determines if certain flags are set.
slapi_attr_free() Frees an attribute.
slapi_attr_get_bervals_copy() Puts the values contained in an attribute into an array of berval structures.
slapi_attr_get_flags() Gets the flags associated with an attribute.
slapi_attr_get_numvalues() Puts the count of values of an attribute into an integer.
slapi_attr_get_oid_copy() Searches for an attribute type and gives its OID string.
slapi_attr_get_type() Gets the name of the attribute type.
slapi_attr_get_valueset() Copies attribute values into a valueset.
slapi_attr_init() Initializes an empty attribute.
slapi_attr_new() Creates a new attribute.
slapi_attr_next_value() Gets the next value of an attribute.
slapi_attr_set_valueset() Initializes a valueset in a Slapi_Attr structure from a specified Slapi_ValueSet structure.
slapi_attr_syntax_normalize() Returns a copy of the normalized attribute types.
slapi_attr_type2plugin() Gets information about the plug-in responsible for handling an attribute type.
slapi_attr_type_cmp() Compares two attributes.
slapi_attr_types_equivalent() Compares two attribute names to determine if they represent the same attribute.
slapi_attr_value_cmp() Compares two attribute values.
slapi_attr_value_find() Determines if an attribute contains a given value.
Section 19.23, “slapi_valueset_set_from_smod()” Adds the changes in a modification to a valueset.
slapi_valueset_set_valueset() Initializes a Slapi_ValueSet structure from another Slapi_ValueSet structure.

19.1. slapi_attr_add_value()

Description

Adds a value to an attribute.

Syntax

#include "slapi-plugin.h"
int slapi_attr_add_value(Slapi_Attr *a, const Slapi_Value *v);

Parameters

This function takes the following parameters:

a The attribute that will contain the values.
v Values to be added to the attribute.
Returns

This function always returns 0.

19.2. slapi_attr_basetype()

Description

This function returns the base type of an attribute (for example, if given cn;lang-jp, returns cn).

Syntax

#include "slapi-plugin.h"
char *slapi_attr_basetype( char *type, char *buf, size_t bufsiz );

Parameters

This function takes the following parameters:

type Attribute type from which you want to get the base type.
buf Buffer to hold the returned base type.
bufsiz Size of the buffer.
Returns

This function returns NULL if the base type fits in the buffer. If the base type is longer than the buffer, the function allocates memory for the base type and returns a pointer to it.

Memory Concerns

You should free the returned base type when done by calling slapi_attr_basetype().

19.3. slapi_attr_dup()

Description

Use this function to make a copy of an attribute.

Syntax

#include "slapi-plugin.h"
Slapi_Attr *slapi_attr_dup(const Slapi_Attr *attr);

Parameters

This function takes the following parameters:

attr The attribute to be duplicated.
Returns

This function returns the newly created copy of the attribute.

Memory Concerns

You must free the returned attribute using slapi_attr_free().

19.4. slapi_attr_first_value()

Description

Use this function to get the first value of an attribute. This is part of a set of functions to enumerate over an Slapi_Attr structure.

Syntax

#include "slapi-plugin.h"
int slapi_attr_first_value( Slapi_Attr *a, Slapi_Value **v );

Parameters

This function takes the following parameters:

a Attribute containing the desired value.
v Holds the first value of the attribute.
Returns

This function returns one of the following values:

  • 0, which is the index of the first value.
  • -1 if the attribute (a) is NULL or if the value (v) parameter has no value.

19.5. slapi_attr_flag_is_set()

Description

This function determines if certain flags are set for a particular attribute. These flags can identify an attribute as a single-valued attribute, an operational attribute, or as a read-only attribute.

Syntax

#include "slapi-plugin.h"int slapi_attr_flag_is_set( const Slapi_Attr *attr, unsigned long flag );

Parameters

This function takes the following parameters:

attr Attribute that you want to check.
flag Flag to check in the attribute.
The value of the flag argument can be one of the following:
SLAPI_ATTR_FLAG_SINGLE Flag that determines if the attribute is single-valued.
SLAPI_ATTR_FLAG_OPATTR Flag that determines if the attribute is an operational attribute.
SLAPI_ATTR_FLAG_READONLY Flag that determines if the attribute is read-only.
Returns

This function returns one of the following values:

  • 1 if the specified flag is set.
  • 0 if the specified flag is not set.

19.6. slapi_attr_free()

Description

Use this function to free an attribute when you are finished with it.

Syntax

#include "slapi-plugin.h"
void slapi_attr_free( Slapi_Attr **a );

Parameters

This function takes the following parameters:

a Attribute to be freed.

19.7. slapi_attr_get_bervals_copy()

Description

This function copies the values from an attribute into an array of berval structure pointers.

Syntax

#include "slapi-plugin.h"
int slapi_attr_get_bervals_copy( Slapi_Attr *a, struct berval ***vals );

Parameters

This function takes the following parameters:

a Attribute that contains the desired values.
vals Pointer to an array of berval structure pointers to hold the desired values.
Returns

This function returns one of the following values:

  • 0 if values are found.
  • -1 if null.
Memory Concerns

You should free this array using ber_bvecfree from the LDAP SDK for C.

19.8. slapi_attr_get_flags()

Description

This function gets the flags associated with the specified attribute. These flags can identify an attribute as a single-valued attribute, an operational attribute, or as a read-only attribute.

Syntax

#include "slapi-plugin.h"
int slapi_attr_get_flags( const Slapi_Attr *attr, unsigned long *flags );

Parameters

This function takes the following parameters:

attr Attribute for which you want to get the flags.
flags When you call slapi_attr_get_flags(), this parameter is set to a pointer to the flags of the specified attribute. Do not free the flags; the flags are part of the actual data in the attribute, not a copy of the data.
To determine which flags have been set, you can bitwise AND the value of the flags argument with one or more of the following:
SLAPI_ATTR_FLAG_SINGLE Flag that determines if the attribute is single-valued.
SLAPI_ATTR_FLAG_OPATTR Flag that determines if the attribute is an operational attribute.
SLAPI_ATTR_FLAG_READONLY Flag that determines if the attribute is read-only.
Returns

This function returns 0 if successful.

19.9. slapi_attr_get_numvalues()

Description

This function counts the number of values in an attribute and places that count in an integer.

Syntax

#include "slapi-plugin.h"
int slapi_attr_get_numvalues( const Slapi_Attr *a, int *numValues);

Parameters

This function takes the following parameters:

a Attribute containing the values to be counted.
numValues Integer to hold the counted values.
Returns

This function always returns 0.

19.10. slapi_attr_get_oid_copy()

Description

This function replaces the deprecated function, slapi_attr_get_oid. Use this function to search the syntaxes for an attribute type's OID and return a copy of it's OID string.

Syntax

#include "slapi-plugin.h"
int slapi_attr_get_oid_copy( const Slapi_Attr *attr, char **oidp );

Parameters

This function takes the following parameters:

attr Attribute that contains the desired type.
oidp Destination string of the copied attribute type OID.
Returns

This function returns one of the following values:

  • 0 if the attribute type is found.
  • -1 if it is not.
Memory Concerns

You should free this string using slapi_ch_free().

19.11. slapi_attr_get_type()

Description

Gets the name of the attribute type from a specified attribute.

Syntax

#include "slapi-plugin.h"
int slapi_attr_get_type( Slapi_Attr *attr, char **type );

Parameters

This function takes the following parameters:

attr Attribute for which you want to get the type.
type When you call slapi_attr_get_type(), this parameter is set to a pointer to the type of the specified attribute. Do not free this attribute type; the type is part of the actual data in the attribute, not a copy of the data.
Returns

This function returns 0 if successful.

19.12. slapi_attr_get_valueset()

Description

Copies existing values contained in an attribute into a valueset.

Syntax

#include "slapi-plugin.h"
int slapi_attr_get_valueset(const Slapi_Attr *a, Slapi_ValueSet **vs);

Parameters

This function takes the following parameters:

a Attribute containing the values to be placed into a valueset.
vs Receives values from the first parameter.
Returns

This function always returns 0.

19.13. slapi_attr_init()

Description

Use this function to initialize an empty attribute with an attribute type.

Syntax

#include "slapi-plugin.h"
Slapi_Attr *slapi_attr_init(Slapi_Attr *a, const char *type);

Parameters

This function takes the following parameters:

a The empty attribute to be initialized.
type Attribute type to be initialized.
Returns

This function returns the newly-initialized attribute.

19.14. slapi_attr_new()

Description

Use this function to create an empty attribute.

Syntax

#include "slapi-plugin.h"
Slapi_Attr *slapi_attr_new( void );

Parameters

This function takes no parameters.

Returns

This function returns the newly-created attribute.

19.15. slapi_attr_next_value()

Description

Use this function to get the next value of an attribute. The value of an attribute associated with an index is placed into a value. This is part of a set of functions to enumerate over a Slapi_Attr structure.

Syntax

#include "slapi-plugin.h"
int slapi_attr_next_value( Slapi_Attr *a, int hint, Slapi_Value **v );

Parameters

This function takes the following parameters:

a Attribute contained the desired value.
hint Index of the value to be returned.
v Holds the value of the attribute.
Returns

This function returns one of the following values:

  • hint plus 1 if the value is found.
  • -1 if null or if a value at hint is not found.

19.16. slapi_attr_set_valueset()

Description

This function initializes a valueset in a Slapi_Attr structure from a specified Slapi_ValueSet structure; the valueset in Slapi_Attr will be *vs, not a copy.

Syntax

#include "slapi-plugin.h"
int slapi_attr_set_valueset(Slapi_Attr *a, const Slapi_ValueSet *vs);

Parameters

This function takes the following parameters:

a Pointer to the Slapi_Attr structure, the valueset of which you wish to set.
vs Pointer to the Slapi_ValueSet structure from which you want to extract the values.
Returns

This function returns 0 unconditionally.

19.17. slapi_attr_syntax_normalize()

Description

Use this function to search the syntaxes for an attribute type and return its normalized form.

Syntax

#include "slapi-plugin.h"
char * slapi_attr_syntax_normalize( const char *s );

Parameters

This function takes the following parameters:

s Attribute type for which you wish to search.
Returns

This function returns the copy of the desired normalized attribute or a normalized copy of what was passed in.

Memory Concerns

You should free the returned string using slapi_ch_free()

See Also

slapi_ch_free()

19.18. slapi_attr_type2plugin()

Description

Gets a pointer to information about the syntax plug-in responsible for handling the specified attribute type. Syntax plug-ins are plug-ins that you can write to index and search for specific attribute types.

Syntax

#include "slapi-plugin.h"
int slapi_attr_type2plugin( const char *type, void **pi );

Parameters

This function takes the following parameters:

type Type of attribute for which you want to get the plug-in.
pi Pointer to the plug-in structure.
Returns

This function returns one of the following values:

  • 0 if successful.
  • -1 if the corresponding plug-in is not found.

19.19. slapi_attr_type_cmp()

Description

Compares two attribute types to determine if they are the same.

Syntax

#include "slapi-plugin.h"
int slapi_attr_type_cmp( const char *t1, const char *t2, int opt );

Parameters

This function takes the following parameters:

t1 Name of the first attribute type that you want to compare.
t2 Name of the second attribute type that you want to compare.
opt One of the following values:
  • 0- Compare the types as-is.
  • 1- Compare only the base names of the types (for example, if the type is cn;lang-en, the function compares only the cn part of the type).
  • 2- Ignore any options in the second type that are not in the first type. For example, if the first type is cn and the second type is cn;lang-en, the lang-en option in the second type is not part of the first type. In this case, the function considers the two types to be the same.
Returns

This function returns one of the following values:

  • 0 if the type names are equal.
  • A non-zero value if the type names are not equal.

19.20. slapi_attr_types_equivalent()

Description

Compares two attribute names to determine if they represent the same attribute.

Syntax

#include "slapi-plugin.h"
int slapi_attr_types_equivalent( const char *t1, const char *t2 );

Parameters

This function takes the following parameters:

t1 Pointer to the first attribute type that you want to compare.
t2 Pointer to the second attributed type that you want to compare.
Returns

This function returns one of the following values:

  • 1 if t1 and t2 represent the same attribute.
  • 0 if t1 and t2 do not represent the same attribute.

19.21. slapi_attr_value_cmp()

Description

Compares two values for a given attribute to determine if they are equal.

Syntax

#include "slapi-plugin.h"
int slapi_attr_value_cmp( const Slapi_Attr *attr, const struct berval *v1, const struct berval *v2 );

Parameters

This function takes the following parameters:

attr Attribute used to determine how these values are compared; for example, if the attribute contains case-insensitive strings, the strings are compared without regard to case.
v1 Pointer to the structure containing the first value that you want to compare.
v2 Pointer to the structure containing the second value that you want to compare.
Returns

This function returns one of the following values:

  • 0 if the values are equal.
  • -1 if the values are not equal.

19.22. slapi_attr_value_find()

Description

Determines if an attribute contains a given value.

Syntax

#include "slapi-plugin.h"
int slapi_attr_value_find( const Slapi_Attr *a, const struct berval *v );

Parameters

This function takes the following parameters:

a Attribute that you want to check.
v Pointer to the berval structure containing the value for which you want to search.
Returns

This function returns one of the following values:

  • 0 if the attribute contains the specified value.
  • -1 if the attribute does not contain the specified value.

19.23. slapi_valueset_set_from_smod()

Adds the changes in a modification to a valueset. Use this function to create a value set that contains the changes from smod.
Syntax

#include "slapi-plugin.h"
void slapi_valueset_set_from_smod(Slapi_ValueSet *vs, Slapi_Mod *smod);

Parameters

This function takes the following parameters:

vs The valueset that will receive changes.
smod Holds the changes to an attribute.

Chapter 20. Functions for Managing Backend Operations

This chapter contains reference information on routines that help you deal with backends.

Table 20.1. Backend Routines

Function Description
slapi_be_addsuffix() Adds the specified suffix to the given backend and increments the backend's suffix count.
slapi_be_delete_onexit() Sets the flag to denote that the backend will be deleted on exiting.
slapi_be_exist() Checks if the backend that contains the specified DN exists.
slapi_be_free() Frees memory and linked resources from the backend structure.
slapi_be_get_instance_info() Gets the instance information of the specified backend.
slapi_be_get_name() Returns the name of the specified backend.
slapi_be_get_readonly() Indicates if the database associated with the backend is in read-only mode.
slapi_be_getentrypoint() Sets pointer to a callback function that corresponds to the specified entry point into a given backend.
slapi_be_getsuffix() Returns the n+1 suffix associated with the specified backend.
slapi_be_gettype() Returns the type of the backend.
slapi_be_is_flag_set() Checks if a flag is set in the backend configuration.
slapi_be_issuffix() Verifies that the specified suffix matches a registered backend suffix.
slapi_be_logchanges() Indicates if the changes applied to the backend should be logged in the changelog.
slapi_be_new() Creates a new backend structure, allocates memory for it, and initializes values for relevant parameters.
slapi_be_private() Verifies if the backend is private.
slapi_be_select() Finds the backend that should be used to service the entry with the specified DN.
slapi_be_select_by_instance_name() Find the backend used to service the database.
slapi_be_set_flag() Sets the specified flag in the backend.
slapi_be_set_instance_info() Sets the instance information of the specified backend with given data.
slapi_be_set_readonly() Sets a flag to denote that the backend is meant to be read-only.
slapi_be_setentrypoint() Sets the entry point in the backend to the specified function.
slapi_get_first_backend() Returns a pointer of the backend structure of the first backend.
slapi_get_first_suffix() Returns the first root suffix of the DIT.
slapi_get_next_backend() Returns a pointer to the next backend.
slapi_get_next_suffix() Returns the DN of the next root suffix of the DIT.
slapi_is_root_suffix() Checks if a suffix is a root suffix of the DIT.
slapi_register_backend_state_change() Registers for callbacks when a backend changes state.
slapi_unregister_backend_state_change() Unregisters backend-state-change callbacks.

20.1. slapi_be_addsuffix()

Description

Adds the specified suffix to the given backend and increments the backend's suffix count.

Syntax

#include "slapi-plugin.h"
void slapi_be_addsuffix(Slapi_Backend *be,const Slapi_DN *suffix);

Parameters

This function takes the following parameters:

be Pointer to the structure containing the backend configuration.
suffix Suffix that needs to be added to the backend.

20.2. slapi_be_delete_onexit()

Description

Sets the flag to denote that the backend will be deleted on exiting.

Syntax

#include "slapi-plugin.h"
void slapi_be_delete_onexit(Slapi_Backend *be);

Parameters

This function takes the following parameter:

be Pointer to the structure containing the backend configuration.

20.3. slapi_be_exist()

Description

Checks if the backend that contains the specified DN exists.

Syntax

#include "slapi-plugin.h"
int slapi_be_exist(const Slapi_DN *sdn);

Parameters

This function takes the following parameter:

sdn Pointer to the DN in the backends for which you are looking.
Returns

This function returns one of the following values:

  • 1 if the backend containing the specified DN exists.
  • 0 if the backend does not exist.

20.4. slapi_be_free()

Description

Frees memory and linked resources from the backend structure.

Syntax

#include "slapi-plugin.h"
void slapi_be_free(Slapi_Backend **be);

Parameters

This function takes the following parameter:

be Pointer to the structure containing the backend configuration.

20.5. slapi_be_get_instance_info()

Description

Gets the instance information of the specified backend.

Syntax

#include "slapi-plugin.h"
void * slapi_be_get_instance_info(Slapi_Backend * be);

Parameters

This function takes the following parameter:

be Pointer to the structure containing the backend configuration.
Returns

This function returns an opaque pointer to the instance information.

20.6. slapi_be_get_name()

Description

Returns the name of the specified backend.

Syntax

#include "slapi-plugin.h"
char * slapi_be_get_name(Slapi_Backend * be);

Parameters

This function takes the following parameter:

be Pointer to the structure containing the backend configuration.
Returns

This function returns the name associated to the specified backend.

Memory Concerns

You should not free the returned pointer.

20.7. slapi_be_get_readonly()

Description

Indicates if the database associated with the backend is in read-only mode.

Syntax

#include "slapi-plugin.h"
int slapi_be_get_readonly(Slapi_Backend *be);

Parameters

This function takes the following parameter:

be Pointer to the structure containing the backend configuration.
Returns

This function returns one of the following values:

  • 0 if the database is not in read-only mode.
  • 1 if the database is in read-only mode.

20.8. slapi_be_getentrypoint()

Description

Sets pointer to a callback function that corresponds to the specified entry point into a given backend.

Syntax

int slapi_be_getentrypoint(Slapi_Backend *be, int entrypoint, 
void **ret_fnptr, Slapi_PBlock *pb);

Parameters

This function takes the following parameters:

be Pointer to the structure containing the backend configuration.
entrypoint Entry point in the backend.
ret_fnptr Opaque pointer to store function address.
pb Pointer to the parameter block.
Returns

This function returns 0 if successful, -1 otherwise.

20.9. slapi_be_getsuffix()

Description

This function returns the n+1 suffix associated with the specified backend. This function is still present for compatibility purposes with previous versions of the Directory Server Plug-in API. Current versions of Directory Server do not support backends containing multiple suffixes; so, if n is not 0, NULL will be returned.

Syntax

#include "slapi-plugin.h"
const Slapi_DN *slapi_be_getsuffix(Slapi_Backend *be, int n);

Parameters

This function takes the following parameters:

be Pointer to the structure containing the backend configuration.
n Index.
Returns

This function returns the DN of the suffix if it exists, or NULL if there is no n+1 suffix in the backend.

Memory Concerns

You should not free the returned pointer.

20.10. slapi_be_gettype()

Description

Returns the type of the backend.

Syntax

#include "slapi-plugin.h"
const char * slapi_be_gettype(Slapi_Backend *be);;

Parameters

This function takes the following parameter:

be Pointer to the structure containing the backend configuration.
Returns

This function returns the type of the backend.

Memory Concerns

You should not free the returned pointer.

20.11. slapi_be_is_flag_set()

Description

Checks if a flag is set in the backend configuration.

Syntax

#include "slapi-plugin.h"
int slapi_be_is_flag_set(Slapi_Backend * be, int flag);

Parameters

This function takes the following parameters:

be Pointer to the structure containing the backend configuration.
flag Flag to check; for example, SLAPI_BE_FLAG_REMOTE_DATA.
Returns

This function returns one of the following values:

  • 0 if a flag is not set in the backend configuration.
  • 1 if a flag is set in the backend configuration.

20.12. slapi_be_issuffix()

Description

This function checks if the specified suffix exactly matches a registered suffix on a specified backend.

Syntax

#include "slapi-plugin.h"
int slapi_be_issuffix(const Slapi_Backend *be, const Slapi_DN *suffix );

Parameters

This function takes the following parameters:

be Pointer to the structure containing the backend configuration.
suffix DN of the suffix for which you are looking.
Returns

This function returns one of the following values:

  • 0 if the suffix is not part of the specified backend.
  • 1 if the suffix is part of the specified backend.

20.13. slapi_be_logchanges()

Description

Indicates whether the changes applied to the backend should be logged in the changelog.

Syntax

#include "slapi-plugin.h"
int slapi_be_logchanges(Slapi_Backend *be);

Parameters

This function takes the following parameter:

be Pointer to the structure containing the backend configuration.
Returns

This function returns one of the following values:

  • 0 if the changes applied to the specific backend should not be logged in the changelog.
  • 1 if the changes should be logged in the changelog.

20.14. slapi_be_new()

Description

Creates a new backend structure, allocates memory for it, and initializes values for relevant parameters.

Syntax

#include "slapi-plugin.h"
Slapi_Backend *slapi_be_new( const char *type, const char *name, int is private, int logchanges );

Parameters

This function takes the following parameters:

type Database type.
name Database name.
isprivate Flag to denote whether the database is private.
logchanges Flag for indicating whether changes are to be logged.
Returns

This function returns a pointer to the newly-created backend.

20.15. slapi_be_private()

Description

Verifies if the backend is private.

Syntax

#include "slapi-plugin.h"
int slapi_be_private( Slapi_Backend *be );

Parameters

This function takes the following parameter:

be Pointer to the structure containing the backend configuration.
Returns

This function returns one of the following values:

  • 0 if the backend is not hidden from the user.
  • 1 if the backend is hidden from the user (for internal use only).

20.16. slapi_be_select()

Description

Finds the backend that should be used to service the entry with the specified DN.

Syntax

#include "slapi-plugin.h"
Slapi_Backend *slapi_be_select( const Slapi_DN * sdn );

Parameters

This function takes the following parameter:

sdn Pointer to the DN of which you wish to get the backend.
Returns

This function returns one of the following values:

  • A pointer to the default backend if no backend with the appropriate suffix is configured.
  • A pointer to the backend structure.
Memory Concerns

You should not free the returned pointer.

20.17. slapi_be_select_by_instance_name()

Description

This function finds the backend that should be used to service the database named as the parameter.

Syntax

#include "slapi-plugin.h"
Slapi_Backend *slapi_be_select_by_instance_name( const char *name );

Parameters

This function takes the following parameter:

name Pointer to the name of the backend of which you wish to get the structure.
Returns

This function returns one of the following values:

  • NULL if no backend with the appropriate name is configured.
  • A pointer to the backend structure.
Memory Concerns

You should not free the returned pointer.

20.18. slapi_be_set_flag()

Description

Sets the specified flag in the backend.

Syntax

#include "slapi-plugin.h"
void slapi_be_set_flag(Slapi_Backend * be, int flag);

Parameters

This function takes the following parameters:

be Pointer to the structure containing the backend configuration.
flag Flag (bitmap) to set in the configuration.

20.19. slapi_be_set_instance_info()

Description

Sets the instance information of the specified backend with given data.

Syntax

#include "slapi-plugin.h"
void slapi_be_set_instance_info(Slapi_Backend * be, void * data);

Parameters

This function takes the following parameters:

be Pointer to the structure containing the backend configuration.
data Data for setting the instance information.

20.20. slapi_be_set_readonly()

Description

Sets a flag to denote that the backend is meant tobe read-only.

Syntax

#include "slapi-plugin.h"
void slapi_be_set_readonly(Slapi_Backend *be, int readonly);

Parameters

This function takes the following parameters:

be Pointer to the structure containing the backend configuration.
readonly Flag to specify the read-only status.

20.21. slapi_be_setentrypoint()

Description

Sets the entry point in the backend to the specified function.

Syntax

#include "slapi-plugin.h"
int slapi_be_setentrypoint(Slapi_Backend *be, int entrypoint, void *ret_fnptr, Slapi_PBlock *pb);

Parameters

This function takes the following parameters:

be Pointer to the structure containing the backend configuration.
entrypoint Entry point in the backend.
ret_fnptr Opaque pointer to store function address.
pb Pointer to the parameter block.
Returns

This function returns 0 if successful, -1 otherwise.

20.22. slapi_get_first_backend()

Description

This function returns a pointer to the backend structure of the first backend. If you wish to iterate through all of the backends, use this function in conjunction with slapi_get_next_backend(). For example:

				Slapi_Backend *be = NULL;
				char *cookie = NULL;
				be = slapi_get_first_backend (&cookie);
				while (be )
				{ 	
				...
				be = slapi_get_next_backend (cookie);
				}
				slapi_ch_free ((void**)&cookie);
Syntax

#include "slapi-plugin.h"
Slapi_Backend* slapi_get_first_backend(char **cookie);

Parameters

This function takes the following parameter:

cookie Output parameter containing the index of the returned backend. This is useful for calls to slapi_get_next_backend(). Contains 0 in output if no backend is returned.
Returns

This function returns one of the following values:

  • A pointer to the backend structure of the first backend and its index in the cookie parameter.
  • NULL if there is no backend.
Memory Concerns

Free the cookie parameter after the iteration using slapi_ch_free().

20.23. slapi_get_first_suffix()

Description

This function returns the first root suffix of the DIT. If you wish to iterate through all of the suffixes, use this function in conjunction with slapi_get_next_suffix(). For example:

				void *node = NULL;
				Slapi_DN * suffix = slapi_get_first_suffix (&node, 1);
				while (suffix)
				{
				...
				suffix = slapi_get_next_suffix (&node, 1);
				}
Syntax

#include "slapi-plugin.h"
Slapi_DN * slapi_get_first_suffix(void ** node, int show_private);

Parameters

This function takes the following parameter:

node Contains the returned valued, which is the DN of the first root suffix of the DIT.
show_private 0 checks only for non-private suffixes.1 checks for both private and non-private suffixes.
Returns

This function returns the DN of the first root suffix.

Memory Concerns

You should not free the returned pointer.

20.24. slapi_get_next_backend()

Description

This function returns a pointer to the next backend. If you wish to iterate through all of the backends, use this function in conjunction with slapi_get_first_backend(). For example:

				Slapi_Backend *be = NULL;
				char *cookie = NULL;
				be = slapi_get_first_backend (&cookie);
				while (be )
				{
				...
				be = slapi_get_next_backend (cookie);
				}
				slapi_ch_free ((void**)&cookie);
Syntax

#include "slapi-plugin.h"
Slapi_Backend* slapi_get_next_backend(char *cookie);

Parameters

This function takes the following parameter:

cookie Upon input, contains the index from which the search for the next backend is done. Upon output, contains the index of the returned backend.
Returns

This function returns one of the following values:

  • A pointer to the next backend, if it exists, and updates the cookie parameter.
  • NULL, and cookie is not changed.
Memory Concerns

Free the cookie parameter after the iteration using slapi_ch_free().

20.25. slapi_get_next_suffix()

Description

This function returns the DN of the next root suffix of the DIT. If you wish to iterate through all of the suffixes, use this function in conjunction with slapi_get_first_suffix(). For example:

				void *node = NULL;
				Slapi_DN * suffix = slapi_get_first_suffix (&node, 1);
				while (suffix)
				{
				...
				suffix = slapi_get_next_suffix (&node, 1);
				}
Syntax

#include "slapi-plugin.h"
Slapi_DN * slapi_get_next_suffix(void ** node, int show_private);

Parameters

This function takes the following parameter:

show_private 0 checks only for non-private suffixes.1 checks for both private and non-private suffixes.
node Contains the returned valued, which is the DN of the next root suffix of the DIT.
Returns

This function returns one of the following values:

  • The DN of the next root suffix of the DIT.
  • NULL if there are more suffixes to parse.
Memory Concerns

You should not free the returned pointer.

20.26. slapi_is_root_suffix()

Description

Checks if a suffix is a root suffix of the DIT.

Syntax

#include "slapi-plugin.h"
int slapi_is_root_suffix(Slapi_DN * dn);

Parameters

This function takes the following parameter:

dn DN to check.
Returns

This function returns one of the following values:

  • 0 if the DN is not a root suffix.
  • 1 if the DN is a root suffix.

20.27. slapi_register_backend_state_change()

Description

This function enables a plug-in to register for callback when the state of a backend changes. The function will come handy when developing custom plug-ins.

For example, if your plug-in stores any kind of state, such as a configuration cache, it will become invalidated or incomplete whenever the state of a backend changes. Because the plug-in wouldn't be aware of these state changes, it would require restarting the server whenever a backend state changed.
By registering for callback whenever the backend changes its state, your plug-in can keep track of these changes and retain its functionality. You can use slapi_unregister_backend_state_change() to unregister the callback.
Syntax

#include "slapi-plugin.h"
void slapi_register_backend_state_change(void * handle, slapi_backend_state_change_fnptr funct);

Parameters

This function takes the following parameter:

handle
Pointer or reference to the address of the specified function.

20.28. slapi_unregister_backend_state_change()

Description

This function enables a plug-in to unregister backend-state-change callback. Use this function to unregister the callback, which is registered using slapi_register_backend_state_change().

Syntax

#include "slapi-plugin.h"
int slapi_unregister_backend_state_change(void * handle);

Parameters

This function takes the following parameter:

handle
Pointer or reference to the address of the specified function.
Returns

This function returns one of the following values:

  • 0 if the specified callback was found and unregistered successfully.
  • 1 if the specified callback wasn't unregistered successfully; for example, if it were not found.

Chapter 21. Functions for Dealing with Controls

This chapter contains reference information on routines for dealing with controls.

Table 21.1. Routines for Dealing with Controls

Function Description
slapi_add_control_ext() Adds the specified control to the end of an array of controls.
slapi_add_controls() Appends all of an array of controls to an existing array of controls.
slapi_build_control() Creates an LDAPControl structure based on a BerElement, an OID, and a criticality flag.
slapi_build_control_from_berval() Creates an LDAPControl structure based on a struct berval, an OID, and a criticality flag.
slapi_control_present() Determines whether the specified object identification (OID) identifies a control that is present in a list of controls.
slapi_dup_control() Makes an allocated copy of an LDAPControl.
slapi_get_supported_controls_copy() Retrieves an allocated array of object identifiers (OIDs) representing the controls supported by the Directory Server.
slapi_register_supported_control() Registers the specified control with the server. This function associates the control with an object identification (OID).

21.1. slapi_add_control_ext()

This function specifies an LDAPControl, and then appends the control to the end of a specified array or creates a new array. For example:
slapi_add_control_ext(&ctrls, newctrl, 1);
An existing array is grown using slapi_ch_realloc(). Otherwise, a new array is created using slapi_ch_malloc().
Syntax

#include "slapi-plugin.h"
void slapi_add_control_ext(LDAPControl ***ctrlsp, LDAPControl *newctrl, int copy)

Parameters

This function takes the following parameters:

ctrlsp Pointer that will receive the specified LDAPControl. If ctrls is NULL, then the array is created using slapi_ch_malloc().
newctrl Pointer to the specified LDAPControl.
copy Sets whether the given control is copied. If the value is true (0), then the control in newctrl is copied. If the value is false (1), then the control in newctrl is used and owned by the array and must be freed using ldap_controls_free.
Returns

This function returns LDAP_SUCCESS (LDAP result code) if successful.

See Also

21.2. slapi_add_controls()

This function specifies an array of LDAPControls, and then either appends the array to the end of a specified array or uses it to create a new array.
An existing array is grown using slapi_ch_realloc(). Otherwise, a new array is created using slapi_ch_malloc().
Syntax

#include "slapi-plugin.h"
void slapi_add_controls(LDAPControl ***ctrlsp, LDAPControl **newctrls, int copy)

Parameters

This function takes the following parameters:

ctrlsp Pointer that will receive the specified LDAPControl array. If ctrls is NULL, then a new array is created using slapi_ch_malloc().
newctrasl The specified LDAPControl array.
copy Sets whether the given controls are copied. If the value is true (0), then all of the controls in newctrls are copied. If the value is false (1), then all of the controls in newctrls are used and owned by the array and must be freed using ldap_controls_free.
Returns

This function returns LDAP_SUCCESS (LDAP result code) if successful.

See Also

21.3. slapi_build_control()

This function creates an LDAPControl structure based on a BerElement, an OID, and a criticality flag. The LDAPControl that is created can be used in LDAP client requests or internal operations.
Syntax

#include "slapi-plugin.h"
int slapi_build_control( char *oid, BerElement *ber, char iscritical, LDAPControl **ctrlp );

Parameters

This function takes the following parameters:

oid
The OID (object identifier) for the control that is to be created.
ber
A BerElement that contains the control value. Pass NULL if the control has no value.
iscritical
The criticality flag. If non-zero, the control will be marked as critical. If 0, it will not be marked as critical.
ctrlp
Pointer that will receive the allocated LDAPControl structure.
Returns

This function returns LDAP_SUCCESS (LDAP result code) if successful.

Memory Concerns

The contents of the ber parameter are consumed by this function. Because of this, the caller should not free the BerElement once a successful call has been made to slapi_build_control().

The LDAPControl pointer that is returned in ctrlp should be freed by calling ldap_control_free(), which is an LDAP API function; see the Mozilla LDAP SDK for C Programmer's Guide.
See Also

21.4. slapi_build_control_from_berval()

Description

This function creates an LDAPControl structure based on a struct berval, an OID, and a criticality flag. The LDAPControl that is created can be used in LDAP client requests or internal operations.

Syntax

#include "slapi-plugin.h"
int slapi_build_control_from_berval( char *oid, struct berval *bvp,char iscritical, LDAPControl **ctrlp );

Parameters

This function takes the following parameters:

oid
The OID (object identifier) for the control that is to be created.
bvp
A struct berval that contains the control value. Pass NULL if the control has no value.
iscritical
The criticality flag. If non-zero, the control will be marked as critical. If 0, it will not be marked as critical.
ctrlp
Pointer that will receive the allocated LDAPControl structure.
Returns

This function returns LDAP_SUCCESS (LDAP result code) if successful.

Memory Concerns

The contents of the bvp parameter are consumed by this function. Because of this, the caller should not free the bvp->bv_val pointer once a successful call to this function has been made.

The LDAPControl pointer that is returned in ctrlp should be freed by calling ldap_control_free(), which is an LDAP API function; see the Mozilla LDAP SDK for C Programmer's Guide.
See Also

21.5. slapi_control_present()

Description

Determines whether the specified object identification (OID) identifies a control that is present in a list of controls.

Syntax

#include "slapi-plugin.h"
int slapi_control_present( LDAPControl **controls, char *oid, struct berval **val, int *iscritical );

Parameters

This function takes the following parameters:

controls
List of controls that you want to check.
oid
OID of the control that you want to find.
val
If the control is present in the list of controls, specifies the pointer to the berval structure containing the value of the control.
iscritical
If the control is present in the list of controls, specifies whether the control is critical to the operation of the server:
  • 0 means that the control is not critical to the operation.
  • 1 means that the control is critical to the operation.
Returns

This function returns one of the following values:

  • 1 if the specified control is present in the list of controls.
  • 0 if the control is not present in the list of controls.
Memory Concerns

The val output parameter is set to point into the controls array. A copy of the control value is not made.

21.6. slapi_dup_control()

Description

Makes an allocated copy of an LDAPControl. This function duplicates the contents of an LDAPControl structure. All fields within the LDAPControl are copied to a new, allocated structure, and a pointer to the new structure is returned.

Syntax

#include "slapi-plugin.h"
LDAPControl * slapi_dup_control( LDAPControl *ctrl )

Parameters

This function takes the following parameter:

ctrl
Pointer to an LDAPControl structure whose contents are to be duplicated.
Returns

This function returns one of the following values:

  • A pointer to an allocated LDAPControl structure if successful.
  • NULL if an error occurs.
Memory Concerns

The structure that is returned should be freed by calling ldap_control_free(), which is an LDAP API function; see the Mozilla LDAP SDK for C Programmer's Guide.

See Also

ldap_control_free()

21.7. slapi_get_supported_controls_copy()

Description

This function replaces the deprecated slapi_get_supported_controls() function from previous releases, as it was not multi thread safe. It retrieves an allocated array of object identifiers (OIDs) representing the controls supported by the Directory Server. You can register new controls by calling slapi_register_supported_control().

When you call slapi_register_supported_control() to register a control, you specify the OID of the control and the IDs of the operations that support the control. The server records this information in two arrays; an array of control OIDs and an array of operations that support the control. You can get copies of these arrays by calling slapi_get_supported_controls_copy().
For each OID returned in the ctrloidsp array, the corresponding array element (with the same index) in the ctrlopsp array identifies the operations that support the control. For a list of the possible IDs for the operations, refer to slapi_register_supported_control().
Syntax

#include "slapi-plugin.h"
int slapi_get_supported_controls_copy( char ***ctrloidsp, unsigned long **ctrlopsp );

Parameters

This function takes the following parameters:

ctrloidsp
Pointer to a character array that will receive the set of supported control OIDs. Pass NULL for this parameter if you do not wish to receive the OIDs.
ctrlopsp
Pointer to an unsigned long array that will receive the supported operation values for each control in the ctrloidsp array. Pass NULL for this parameter if you do not wish to receive the supported operation values.
Returns

This function returns one of the following values:

  • 0 if successful.
  • A non-zero value if an error occurs.
Memory Concerns

The returned ctrloidsp array should be freed by calling slapi_ch_array_free(). The returned ctrlopsp array should be freed by calling slapi_ch_free().

21.8. slapi_register_supported_control()

Description

Registers the specified control with the server. This function associates the control with an object identification (OID). When the server receives a request that specifies this OID, the server makes use of this information to determine if the control is supported by the server or its plug-ins.

Syntax

#include "slapi-plugin.h"
void slapi_register_supported_control( char *controloid, unsigned long controlops );

Parameters

This function takes the following parameters:

controloid
OID of the control you want to register.
controlops
Operation to which the control is app