Netscape logo Plug-in Programmer's Guide
Netscape Directory Server                                                                                                                                  

Previous
Contents
Index
DocHome Next

 

Chapter 2   Writing and Compiling Plug-ins



This chapter provides an introduction on how to write and compile Netscape Directory Server (Directory Server) plug-ins. Chapter 3, "Configuring Plug-ins," describes how to load your plug-in into the Directory Server configuration once it is successfully compiled. This chapter covers the following topics:

If you have already written a plug-in for the Directory Server, refer to the section Using Directory Server Plug-in APIs for information on migrating your plug-in to the latest version of the Directory Server.


Writing a Plug-in Function

To write a Directory Server plug-in, you must do the following in your plug-in code:

For additional information on writing specific plug-in types, refer to the following chapters:


Including the API Header File

The interface to the Directory Server plug-in API is located in the slapi-plugin.h header file. You must include this header file in the plug-ins you write. The following line of code shows an example of including this header file:

#include "slapi-plugin.h"

When you install the Directory Server, slapi-plugin.h gets installed into the following directory:

<server_root>/plugins/slapd/slapi/include


Passing Data with Parameter Blocks

Often, plug-in functions make use of a parameter block, Slapi_PBlock, for passing information to and from the Directory Server. The following plug-in function types pass a parameter block as a function argument:

  • Pre-operation plug-in functions.
  • Post-operation plug-in functions.
  • Matching rule functions for indexing.
  • Factory functions for matching rule index functions.
  • Factory functions for matching rule filter functions.

When invoking these types of plug-in functions, you pass to the Directory Server a single argument of type Slapi_PBlock. This argument contains the parameter values needed to complete the function request. Your plug-in function should have a prototype similar to the following:

int myFunction(Slapi_PBlock pb);

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.


Working with Parameter Blocks

In the functions 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 which you can use within your functions. This process is described in the next section, Getting Data from the Parameter Block.

You can also set values in the parameter block during the processing of your plug-in functions. The Directory Server can then use the new data values to complete an operation which it might be processing. For details on this, see Setting Data in the Parameter Block.

Some of the data that you can retrieve from the parameter block include entries, attributes, search filters, and distinguished names (DNs). Once you retrieve 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. For details, see Calling Front-End Functions.


Getting Data from the Parameter Block

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


Note 

Often, slapi_pblock_get() returns a pointer to the actual data. When you call your own 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 the following example, 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. Note that the actual DN (not a copy of it) is normalized and converted to lowercase.

Code Example 2-1   Getting Data from the Parameter Block

#include <slapi-plugin.h>

...

int

searchdn_preop_search( Slapi_PBlock *pb )

{

char *dn;

/* 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 );

 

/* Normalize the DN (the actual DN, not a copy of it)

and convert it to lowercase */

slapi_dn_normalize_case( dn );

 

/* Log the normalized DN */

slapi_log_error( SLAPI_LOG_PLUGIN, "searchdn_preop_search",

"Normalized DN: %s\n", dn );

return( 0 );

}


In this code example, SLAPI_SEARCH_TARGET identifies the parameter in the parameter block that contains the base DN of the search. For a complete listing of the parameter block IDs, see Chapter 16, "Parameter Block Reference."

Setting Data in the Parameter Block

To modify the value of a parameter in the parameter block, call the function slapi_pblock_set(). For example, you call can 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.

Code Example 2-2   Setting Values in the Parameter Block

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

}

...

}


Notice that this example uses the function slapi_new_condvar() 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 Chapter 16, "Parameter Block Reference."


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 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, "Front-End API Functions," and chapter 15, "Function Reference."


Plug-in Return Values

If your 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_new_condvar() to log an error message to describe the problem (Logging Messages details this process).

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, refer to the chapter that documents the type of plug-in you are writing.


Writing Plug-in Initialization Functions

Before the Directory Server can call your plug-in function, the function must be properly initialized. To do this, you must write an initialization function for your server plug-in. The initialization function should do the following:

  1. Specify the plug-in compatibility version.
  2. Register each of your plug-in functions.
  3. Return a value to the Directory Server.

Your initialization function should have a prototype similar to the following:

int my_init_function( Slapi_PBlock pb );

Notice that in the initialization function, the Directory Server passes a single argument of type Slapi_PBlock.

Initialization Functions for Windows Platforms

If you are writing an initialization function for a plug-in that runs on Windows NT or Windows 2000, make sure to export the initialization function. For example:

__declspec(dllexport) int my_init_function(Slapi_PBlock pb);

On top of exporting the initialization function, you must also specify the name of the initialization function in a .def file.

In addition to the initialization function, you might need to export other functions contained in your plug-in. In particular, you will need to export any functions that are not specifically registered by your initialization functions, such as the entry store and entry fetch plug-in functions that are described in chapter 9. Registering plug-in functions is described in detail in the next section, Registering Your Plug-in Functions


Note 

You do not need to export all plug-in functions. Specifically, you do not need to export any plug-in function that is specified in the parameter block.



Specifying Directory Server Compatibility

You need to specify the compatibility version of your plug-in so that the Directory Server can determine whether or not it supports the plug-in.

To specify the plug-in compatibility version, call the slapi_pblock_set() function, and set the SLAPI_PLUGIN_VERSION 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 1 (SLAPI_PLUGIN_VERSION_01) is compatible with versions 3.x and 4.x of the Directory Server.

  • Plug-in version 2 (SLAPI_PLUGIN_VERSION_02) is compatible with version 4.x of the Directory Server.

  • Plug-in version 3 (SLAPI_PLUGIN_VERSION_03) is compatible with versions 6.1 and later of the Directory Server.


Specifying Information about the Plug-in

You specify information about your plug-in, such as a description of the plug-in, with the Slapi_PluginDesc structure. For details on this data structure, see Slapi_PluginDesc.

It is advised that you include a plug-in description since the Netscape 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:

Code Example 2-3   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 your tracking purposes only; it is not the same as the server compatibility version number specified by the SLAPI_PLUGIN_VERSION parameter (see Specifying Directory Server Compatibility for details on this parameter). As you make changes to your 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.


Registering Your Plug-in Functions

Whether you register your plug-in through the initialization function depends upon the type of function you are registering.

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 your 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 your plug-in function.

The full list parameters that you can use to register your plug-in functions are listed in 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 your 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 you do not register your plug-in functions, the Directory Server will not call your plug-in functions. Make sure to register your plug-in functions.


You can register more than one plug-in function in your initialization function; you do not need to write an initialization function for each plug-in function that you need to register. You should, however, define a different initialization function for each type of plug-in that you are registering.


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. If the initialization function returns -1, the Directory Server will exit.


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.

Code Example 2-4   An Example Initialization Function

#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 "01")*/

if ( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION,

SLAPI_PLUGIN_VERSION_01 ) != 0 ||

/* Set up the server 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 registering function.\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 );

}



Compiling a Directory Server Plug-in

Keep in mind the following tips when compiling your server plug-in:

The following code shows a sample Makefile for Solaris. The example assumes that the source files are located in the following directory:

<server_root>/plugins/slapd/slapi/examples

The server plug-in API header files are located in the relative path ../include.

Code Example 2-5   Example Solaris Makefile

# SOLARIS Makefile for Directory Server plug-in examples

#

CC = cc

LD = ld

INCLUDE_FLAGS = -I../include

CFLAGS = $(INCLUDE_FLAGS) -D_REENTRANT -KPIC

LDFLAGS = -G

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




Previous
Contents
Index
DocHome Next

© 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2004 Netscape Communications Corporation. All rights reserved.
Read the Full Copyright and Third-Party Acknowledgments.

last updated November 26, 2004