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.

Note

Previously, Red Hat recommended to use the SLAPI_PLUGIN_EXTENDEDOP parameter to register extended operation plug-ins. However, this function registration point has certain limitations. For example, this function registration is not correctly linked in a back end transaction, which can cause deadlock scenarios. To avoid similar issues, use the SLAPI_PLUGIN_BETXNEXTENDEDOP parameter. This parameter adds a database transaction to the extended operation.
The SLAPI_PLUGIN_EXT_OP_BACKEND_FN parameter enables the plug-in to inform the server which back end will be used. After that, the server initiates a transaction. The following diagram illustrates the process:
Registering Extended Operation Functions

Figure 10.1. Registering Extended Operation Functions

You can write your initialization function so that the OID is passed in from the directive (refer to Section 3.4, “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.
#include "dirsrv/slapi-plugin.h"

/****************************************************
 * Pre Extended Operation, Backend selection
 ***************************************************/
static int extend_exop_backend(Slapi_PBlock *pb, Slapi_Backend **target)
{
    Slapi_DN *shared_sdn = NULL;
    char *shared_dn = NULL;
    int res = -1;
    /* Parse the oid and what exop wants us to do - You need to implement this function! */
    res = parse_exop_ber(pb, &shared_dn);
    if (res == LDAP_SUCCESS && shared_dn) {
            shared_sdn = slapi_sdn_new_dn_byref(shared_dn);
           /* Take the SDN of the operation, and use it to find
              The backend we plan to operate on.
            */
           *target = slapi_be_select(shared_sdn);
           slapi_sdn_free(&shared_sdn);
           res = LDAP_SUCCESS;
    }
    return res;
}


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_initx" , "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_03 ) != 0 ||

         /* Specify the OID of the extended operation */
	 slapi_pblock_set( pb, SLAPI_PLUGIN_EXT_OP_OIDLIST, (void*) oids ) != 0 ||
	 slapi_pblock_set(pb, SLAPI_PLUGIN_EXT_OP_BACKEND_FN, (void *)extend_exop_backend) != 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" , "Plugin successfully 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: beextendedop
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 /usr/lib64/dirsrv/plugins.