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 "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_attribute_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 );
}